From eb020c73e01bc31c9ae8500fa07ecfafcd35d2c8 Mon Sep 17 00:00:00 2001 From: Holger Freyther Date: Sun, 13 Apr 2008 07:25:58 +0100 Subject: [PATCH] [neo] Every access to GPIO bank B has to go through the shadow code - Any setting of any PIN on bank B will undo the LED setting. Introduce neo1973_gpb_set_pin to set the PIN in a way not losing the LED or any other shadowed setting. - Update users of GPBXY for gta01 and gta02. Signed-Off-By: Holger Freyther --- arch/arm/mach-s3c2410/mach-gta01.c | 9 ++-- arch/arm/mach-s3c2440/mach-gta02.c | 10 ++-- arch/arm/plat-s3c24xx/Makefile | 4 +- arch/arm/plat-s3c24xx/neo1973_pm_bt.c | 15 +++--- arch/arm/plat-s3c24xx/neo1973_pm_gps.c | 5 ++- arch/arm/plat-s3c24xx/neo1973_pm_gsm.c | 9 ++-- arch/arm/plat-s3c24xx/neo1973_shadow.c | 86 ++++++++++++++++++++++++++++++++ drivers/leds/leds-neo1973-gta02.c | 12 ++-- drivers/leds/leds-neo1973-vibrator.c | 7 ++- drivers/video/backlight/gta01_bl.c | 9 ++-- include/asm-arm/plat-s3c24xx/neo1973.h | 33 ++++++++++++ 11 files changed, 165 insertions(+), 34 deletions(-) create mode 100644 arch/arm/plat-s3c24xx/neo1973_shadow.c create mode 100644 include/asm-arm/plat-s3c24xx/neo1973.h diff --git a/arch/arm/mach-s3c2410/mach-gta01.c b/arch/arm/mach-s3c2410/mach-gta01.c index a948311..ff08449 100644 --- a/arch/arm/mach-s3c2410/mach-gta01.c +++ b/arch/arm/mach-s3c2410/mach-gta01.c @@ -72,6 +72,7 @@ #include #include #include +#include static struct map_desc gta01_iodesc[] __initdata = { { @@ -416,10 +417,10 @@ static void gta01_mmc_set_power(unsigned char power_mode, unsigned short vdd) case GTA01Bv4_SYSTEM_REV: switch (power_mode) { case MMC_POWER_OFF: - s3c2410_gpio_setpin(GTA01_GPIO_SDMMC_ON, 1); + neo1973_gpb_setpin(GTA01_GPIO_SDMMC_ON, 1); break; case MMC_POWER_ON: - s3c2410_gpio_setpin(GTA01_GPIO_SDMMC_ON, 0); + neo1973_gpb_setpin(GTA01_GPIO_SDMMC_ON, 0); break; } break; @@ -442,10 +443,10 @@ static void gta01_udc_command(enum s3c2410_udc_cmd_e cmd) switch (cmd) { case S3C2410_UDC_P_ENABLE: - s3c2410_gpio_setpin(GTA01_GPIO_USB_PULLUP, 1); + neo1973_gpb_setpin(GTA01_GPIO_USB_PULLUP, 1); break; case S3C2410_UDC_P_DISABLE: - s3c2410_gpio_setpin(GTA01_GPIO_USB_PULLUP, 0); + neo1973_gpb_setpin(GTA01_GPIO_USB_PULLUP, 0); break; default: break; diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c index f9e00d5..27babc9 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -127,11 +128,11 @@ FIQ_HANDLER_ENTRY(256, 512) if (fiq_ipc.vib_pwm_latched || fiq_ipc.vib_pwm) { /* not idle */ if (((u8)_fiq_count_fiqs) == fiq_ipc.vib_pwm_latched) - s3c2410_gpio_setpin(fiq_ipc.vib_gpio_pin, 0); + neo1973_gpb_setpin(fiq_ipc.vib_gpio_pin, 0); if (((u8)_fiq_count_fiqs) == 0) { fiq_ipc.vib_pwm_latched = fiq_ipc.vib_pwm; if (fiq_ipc.vib_pwm_latched) - s3c2410_gpio_setpin(fiq_ipc.vib_gpio_pin, 1); + neo1973_gpb_setpin(fiq_ipc.vib_gpio_pin, 1); } divisor = FIQ_DIVISOR_VIBRATOR; } @@ -319,6 +320,7 @@ FIQ_HANDLER_ENTRY(256, 512) FIQ_HANDLER_END() + /** * returns PCB revision information in b9,b8 and b2,b1,b0 * Pre-GTA02 A6 returns 0x000 @@ -763,10 +765,10 @@ static void gta02_udc_command(enum s3c2410_udc_cmd_e cmd) switch (cmd) { case S3C2410_UDC_P_ENABLE: - s3c2410_gpio_setpin(GTA02_GPIO_USB_PULLUP, 1); + neo1973_gpb_setpin(GTA02_GPIO_USB_PULLUP, 1); break; case S3C2410_UDC_P_DISABLE: - s3c2410_gpio_setpin(GTA02_GPIO_USB_PULLUP, 0); + neo1973_gpb_setpin(GTA02_GPIO_USB_PULLUP, 0); break; case S3C2410_UDC_P_RESET: /* FIXME! */ diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile index e667105..0efcc15 100644 --- a/arch/arm/plat-s3c24xx/Makefile +++ b/arch/arm/plat-s3c24xx/Makefile @@ -32,4 +32,6 @@ obj-$(CONFIG_MACH_NEO1973) += neo1973_version.o \ neo1973_pm_host.o \ neo1973_pm_gsm.o \ neo1973_pm_gps.o \ - neo1973_pm_bt.o + neo1973_pm_bt.o \ + neo1973_shadow.o + diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_bt.c b/arch/arm/plat-s3c24xx/neo1973_pm_bt.c index a9694b4..dfc9ae8 100644 --- a/arch/arm/plat-s3c24xx/neo1973_pm_bt.c +++ b/arch/arm/plat-s3c24xx/neo1973_pm_bt.c @@ -18,6 +18,7 @@ #include #include +#include #ifdef CONFIG_MACH_NEO1973_GTA01 #include @@ -95,20 +96,20 @@ static ssize_t bt_write(struct device *dev, struct device_attribute *attr, /* if we are powering up, assert reset, then power, * then release reset */ if (on) { - s3c2410_gpio_setpin(GTA01_GPIO_BT_EN, 0); + neo1973_gpb_setpin(GTA01_GPIO_BT_EN, 0); pcf50606_voltage_set(pcf50606_global, PCF50606_REGULATOR_D1REG, 3100); } pcf50606_onoff_set(pcf50606_global, PCF50606_REGULATOR_D1REG, on); - s3c2410_gpio_setpin(GTA01_GPIO_BT_EN, on); + neo1973_gpb_setpin(GTA01_GPIO_BT_EN, on); break; #endif /* CONFIG_MACH_NEO1973_GTA01 */ #ifdef CONFIG_MACH_NEO1973_GTA02 case MACH_TYPE_NEO1973_GTA02: - s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, on ? 0 : 1); + neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on ? 0 : 1); if (on) pcf50633_voltage_set(pcf50633_global, PCF50633_REGULATOR_LDO4, 3200); @@ -127,13 +128,13 @@ static ssize_t bt_write(struct device *dev, struct device_attribute *attr, #ifdef CONFIG_MACH_NEO1973_GTA01 case MACH_TYPE_NEO1973_GTA01: - s3c2410_gpio_setpin(GTA01_GPIO_BT_EN, on ? 0 : 1); + neo1973_gpb_setpin(GTA01_GPIO_BT_EN, on ? 0 : 1); break; #endif /* CONFIG_MACH_NEO1973_GTA01 */ #ifdef CONFIG_MACH_NEO1973_GTA02 case MACH_TYPE_NEO1973_GTA02: - s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, on ? 0 : 1); + neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on ? 0 : 1); break; #endif /* CONFIG_MACH_NEO1973_GTA02 */ @@ -192,7 +193,7 @@ static int __init gta01_bt_probe(struct platform_device *pdev) PCF50606_REGULATOR_D1REG, 0); /* we pull reset to low to make sure that the chip doesn't * drain power through the reset line */ - s3c2410_gpio_setpin(GTA01_GPIO_BT_EN, 0); + neo1973_gpb_setpin(GTA01_GPIO_BT_EN, 0); break; #endif /* CONFIG_MACH_NEO1973_GTA01 */ @@ -203,7 +204,7 @@ static int __init gta01_bt_probe(struct platform_device *pdev) PCF50633_REGULATOR_LDO4, 0); /* we pull reset to low to make sure that the chip doesn't * drain power through the reset line */ - s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, 0); + neo1973_gpb_setpin(GTA02_GPIO_BT_EN, 0); break; #endif /* CONFIG_MACH_NEO1973_GTA02 */ diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_gps.c b/arch/arm/plat-s3c24xx/neo1973_pm_gps.c index d882f7b..d020f8d 100644 --- a/arch/arm/plat-s3c24xx/neo1973_pm_gps.c +++ b/arch/arm/plat-s3c24xx/neo1973_pm_gps.c @@ -20,6 +20,9 @@ #include #include + +#include + #ifdef CONFIG_MACH_NEO1973_GTA01 #include #include @@ -264,7 +267,7 @@ static void gps_pwron_set(int on) { #ifdef CONFIG_MACH_NEO1973_GTA01 if (machine_is_neo1973_gta01()) - s3c2410_gpio_setpin(GTA01_GPIO_GPS_PWRON, on); + neo1973_gpb_setpin(GTA01_GPIO_GPS_PWRON, on); #endif /* CONFIG_MACH_NEO1973_GTA01 */ #ifdef CONFIG_MACH_NEO1973_GTA02 diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c b/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c index 5ad942e..149b866 100644 --- a/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c +++ b/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_MACH_NEO1973_GTA02 #include @@ -109,9 +110,9 @@ static ssize_t gsm_write(struct device *dev, struct device_attribute *attr, #endif } - s3c2410_gpio_setpin(GTA01_GPIO_MODEM_ON, 1); + neo1973_gpb_setpin(GTA01_GPIO_MODEM_ON, 1); } else { - s3c2410_gpio_setpin(GTA01_GPIO_MODEM_ON, 0); + neo1973_gpb_setpin(GTA01_GPIO_MODEM_ON, 0); switch (system_rev) { #ifdef CONFIG_MACH_NEO1973_GTA02 @@ -138,9 +139,9 @@ static ssize_t gsm_write(struct device *dev, struct device_attribute *attr, } } else if (!strcmp(attr->attr.name, "reset")) { if (machine_is_neo1973_gta01()) - s3c2410_gpio_setpin(GTA01_GPIO_MODEM_RST, on); + neo1973_gpb_setpin(GTA01_GPIO_MODEM_RST, on); else if (machine_is_neo1973_gta02()) - s3c2410_gpio_setpin(GTA02_GPIO_MODEM_RST, on); + neo1973_gpb_setpin(GTA02_GPIO_MODEM_RST, on); } else if (!strcmp(attr->attr.name, "download")) { if (machine_is_neo1973_gta01()) s3c2410_gpio_setpin(GTA01_GPIO_MODEM_DNLOAD, on); diff --git a/arch/arm/plat-s3c24xx/neo1973_shadow.c b/arch/arm/plat-s3c24xx/neo1973_shadow.c new file mode 100644 index 0000000..09667da --- /dev/null +++ b/arch/arm/plat-s3c24xx/neo1973_shadow.c @@ -0,0 +1,86 @@ +/* + * include/asm-arm/plat-s3c24xx/neo1973.h + * + * Common utility code for GTA01 and GTA02 + * + * Copyright (C) 2008 by Openmoko, Inc. + * Author: Holger Hans Peter Freyther + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include + +/** + * Shadow GPIO bank B handling. For the LEDs we need to keep track of the state + * in software. The s3c2410_gpio_setpin must not be used for GPIOs on bank B + */ +static unsigned long gpb_mask; +static unsigned long gpb_state; + +void neo1973_gpb_add_shadow_gpio(unsigned int gpio) +{ + unsigned long offset = S3C2410_GPIO_OFFSET(gpio); + unsigned long flags; + + local_irq_save(flags); + gpb_mask |= 1L << offset; + local_irq_restore(flags); +} +EXPORT_SYMBOL(neo1973_gpb_add_shadow_gpio); + +static void set_shadow_gpio(unsigned long offset, unsigned int value) +{ + unsigned long state = value != 0; + + gpb_state &= ~(1L << offset); + gpb_state |= state << offset; +} + +void neo1973_gpb_setpin(unsigned int pin, unsigned to) +{ + void __iomem *base = S3C24XX_GPIO_BASE(S3C2410_GPB0); + unsigned long offset = S3C2410_GPIO_OFFSET(pin); + unsigned long flags; + unsigned long dat; + + BUG_ON(base != S3C24XX_GPIO_BASE(pin)); + + local_irq_save(flags); + dat = __raw_readl(base + 0x04); + + /* Add the shadow values */ + dat &= ~gpb_mask; + dat |= gpb_state; + + /* Do the operation like s3c2410_gpio_setpin */ + dat &= ~(1L << offset); + dat |= to << offset; + + /* Update the shadow state */ + if ((1L << offset) & gpb_mask) + set_shadow_gpio(offset, to); + + __raw_writel(dat, base + 0x04); + local_irq_restore(flags); +} +EXPORT_SYMBOL(neo1973_gpb_setpin); diff --git a/drivers/leds/leds-neo1973-gta02.c b/drivers/leds/leds-neo1973-gta02.c index 343550a..952ad69 100644 --- a/drivers/leds/leds-neo1973-gta02.c +++ b/drivers/leds/leds-neo1973-gta02.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MAX_LEDS 3 #define COUNTER 256 @@ -60,14 +61,13 @@ static void gta02led_set(struct led_classdev *led_cdev, * value == 0 -> 0% duty cycle (zero power) */ mutex_lock(&lp->mutex); + if (lp->has_pwm) { - s3c2410_pwm_duty_cycle(value, &lp->pwm); + s3c2410_pwm_duty_cycle(value, &lp->pwm); } else { - if (value) - s3c2410_gpio_setpin(lp->gpio, 1); - else - s3c2410_gpio_setpin(lp->gpio, 0); + neo1973_gpb_setpin(lp->gpio, value ? 1 : 0); } + mutex_unlock(&lp->mutex); } @@ -164,7 +164,7 @@ static int __init gta02led_probe(struct platform_device *pdev) case S3C2410_GPB3: lp->has_pwm = 0; s3c2410_gpio_cfgpin(lp->gpio, S3C2410_GPIO_OUTPUT); - s3c2410_gpio_setpin(lp->gpio, 0); + neo1973_gpb_add_shadow_gpio(lp->gpio); break; default: break; diff --git a/drivers/leds/leds-neo1973-vibrator.c b/drivers/leds/leds-neo1973-vibrator.c index f31302d..647e860 100644 --- a/drivers/leds/leds-neo1973-vibrator.c +++ b/drivers/leds/leds-neo1973-vibrator.c @@ -24,6 +24,7 @@ #include #include +#include #define COUNTER 64 @@ -56,9 +57,9 @@ static void neo1973_vib_vib_set(struct led_classdev *led_cdev, s3c2410_pwm_duty_cycle(value / 4, &vp->pwm); else { if (value) - s3c2410_gpio_setpin(vp->gpio, 1); + neo1973_gpb_setpin(vp->gpio, 1); else - s3c2410_gpio_setpin(vp->gpio, 0); + neo1973_gpb_setpin(vp->gpio, 0); } mutex_unlock(&vp->mutex); @@ -131,7 +132,7 @@ static int __init neo1973_vib_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &neo1973_vib_led); if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */ - s3c2410_gpio_setpin(neo1973_vib_led.gpio, 0); /* off */ + neo1973_gpb_setpin(neo1973_vib_led.gpio, 0); /* off */ s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPIO_OUTPUT); /* safe, kmalloc'd copy needed for FIQ ISR */ fiq_ipc.vib_gpio_pin = neo1973_vib_led.gpio; diff --git a/drivers/video/backlight/gta01_bl.c b/drivers/video/backlight/gta01_bl.c index bd7d41f..301ec9c 100644 --- a/drivers/video/backlight/gta01_bl.c +++ b/drivers/video/backlight/gta01_bl.c @@ -40,6 +40,7 @@ #include #include +#include static struct backlight_properties gta01bl_prop; static struct backlight_device *gta01_backlight_device; @@ -83,12 +84,12 @@ static int gta01bl_send_intensity(struct backlight_device *bd) mutex_lock(>a01bl.mutex); #ifdef GTA01_BACKLIGHT_ONOFF_ONLY if (intensity) - s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 1); + neo1973_gpb_setpin(GTA01_GPIO_BACKLIGHT, 1); else - s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 0); + neo1973_gpb_setpin(GTA01_GPIO_BACKLIGHT, 0); #else if (intensity == bd->props.max_brightness) { - s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 1); + neo1973_gpb_setpin(GTA01_GPIO_BACKLIGHT, 1); s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPIO_OUTPUT); } else { s3c2410_pwm_duty_cycle(intensity & 0xffff, >a01bl.pwm); @@ -222,7 +223,7 @@ static int gta01bl_remove(struct platform_device *dev) mutex_destroy(>a01bl.mutex); s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPIO_OUTPUT); - s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 1); + neo1973_gpb_setpin(GTA01_GPIO_BACKLIGHT, 1); return 0; } diff --git a/include/asm-arm/plat-s3c24xx/neo1973.h b/include/asm-arm/plat-s3c24xx/neo1973.h new file mode 100644 index 0000000..63297de --- /dev/null +++ b/include/asm-arm/plat-s3c24xx/neo1973.h @@ -0,0 +1,33 @@ +/* + * include/asm-arm/plat-s3c24xx/neo1973.h + * + * Common utility code for GTA01 and GTA02 + * + * Copyright (C) 2008 by Openmoko, Inc. + * Author: Holger Hans Peter Freyther + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef NEO1973_H +#define NEO1973_H + +void neo1973_gpb_add_shadow_gpio(unsigned int gpio); +void neo1973_gpb_setpin(unsigned int pin, unsigned to); + +#endif -- 1.5.6.5