diff options
Diffstat (limited to 'arch/arm/mach-sa1100')
-rw-r--r-- | arch/arm/mach-sa1100/assabet.c | 145 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/collie.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/h3100.c | 54 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/h3600.c | 74 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/include/mach/assabet.h | 6 |
5 files changed, 253 insertions, 61 deletions
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index c9808c684152..8443a27bca2f 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -75,12 +75,143 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val) EXPORT_SYMBOL(ASSABET_BCR_frob); +/* + * The codec reset goes to three devices, so we need to release + * the rest when any one of these requests it. However, that + * causes the ADV7171 to consume around 100mA - more than half + * the LCD-blanked power. + * + * With the ADV7171, LCD and backlight enabled, we go over + * budget on the MAX846 Li-Ion charger, and if no Li-Ion battery + * is connected, the Assabet crashes. + */ +#define RST_UCB1X00 (1 << 0) +#define RST_UDA1341 (1 << 1) +#define RST_ADV7171 (1 << 2) + +#define SDA GPIO_GPIO(15) +#define SCK GPIO_GPIO(18) +#define MOD GPIO_GPIO(17) + +static void adv7171_start(void) +{ + GPSR = SCK; + udelay(1); + GPSR = SDA; + udelay(2); + GPCR = SDA; +} + +static void adv7171_stop(void) +{ + GPSR = SCK; + udelay(2); + GPSR = SDA; + udelay(1); +} + +static void adv7171_send(unsigned byte) +{ + unsigned i; + + for (i = 0; i < 8; i++, byte <<= 1) { + GPCR = SCK; + udelay(1); + if (byte & 0x80) + GPSR = SDA; + else + GPCR = SDA; + udelay(1); + GPSR = SCK; + udelay(1); + } + GPCR = SCK; + udelay(1); + GPSR = SDA; + udelay(1); + GPDR &= ~SDA; + GPSR = SCK; + udelay(1); + if (GPLR & SDA) + printk(KERN_WARNING "No ACK from ADV7171\n"); + udelay(1); + GPCR = SCK | SDA; + udelay(1); + GPDR |= SDA; + udelay(1); +} + +static void adv7171_write(unsigned reg, unsigned val) +{ + unsigned gpdr = GPDR; + unsigned gplr = GPLR; + + ASSABET_BCR = BCR_value | ASSABET_BCR_AUDIO_ON; + udelay(100); + + GPCR = SDA | SCK | MOD; /* clear L3 mode to ensure UDA1341 doesn't respond */ + GPDR = (GPDR | SCK | MOD) & ~SDA; + udelay(10); + if (!(GPLR & SDA)) + printk(KERN_WARNING "Something dragging SDA down?\n"); + GPDR |= SDA; + + adv7171_start(); + adv7171_send(0x54); + adv7171_send(reg); + adv7171_send(val); + adv7171_stop(); + + /* Restore GPIO state for L3 bus */ + GPSR = gplr & (SDA | SCK | MOD); + GPCR = (~gplr) & (SDA | SCK | MOD); + GPDR = gpdr; +} + +static void adv7171_sleep(void) +{ + /* Put the ADV7171 into sleep mode */ + adv7171_write(0x04, 0x40); +} + +static unsigned codec_nreset; + +static void assabet_codec_reset(unsigned mask, int set) +{ + unsigned long flags; + bool old; + + local_irq_save(flags); + old = !codec_nreset; + if (set) + codec_nreset &= ~mask; + else + codec_nreset |= mask; + + if (old != !codec_nreset) { + if (codec_nreset) { + ASSABET_BCR_set(ASSABET_BCR_NCODEC_RST); + adv7171_sleep(); + } else { + ASSABET_BCR_clear(ASSABET_BCR_NCODEC_RST); + } + } + local_irq_restore(flags); +} + static void assabet_ucb1x00_reset(enum ucb1x00_reset state) { - if (state == UCB_RST_PROBE) - ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); + int set = state == UCB_RST_REMOVE || state == UCB_RST_SUSPEND || + state == UCB_RST_PROBE_FAIL; + assabet_codec_reset(RST_UCB1X00, set); } +void assabet_uda1341_reset(int set) +{ + assabet_codec_reset(RST_UDA1341, set); +} +EXPORT_SYMBOL(assabet_uda1341_reset); + /* * Assabet flash support code. @@ -155,12 +286,9 @@ static int assabet_irda_set_power(struct device *dev, unsigned int state) 0 }; - if (state < 4) { - state = bcr_state[state]; - ASSABET_BCR_clear(state ^ (ASSABET_BCR_IRDA_MD1| - ASSABET_BCR_IRDA_MD0)); - ASSABET_BCR_set(state); - } + if (state < 4) + ASSABET_BCR_frob(ASSABET_BCR_IRDA_MD1 | ASSABET_BCR_IRDA_MD0, + bcr_state[state]); return 0; } @@ -180,6 +308,7 @@ static struct irda_platform_data assabet_irda_data = { static struct ucb1x00_plat_data assabet_ucb1x00_data = { .reset = assabet_ucb1x00_reset, .gpio_base = -1, + .can_wakeup = 1, }; static struct mcp_plat_data assabet_mcp_data = { diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 7fb96ebdc0fb..831a15824ec8 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -27,6 +27,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/timer.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> #include <linux/gpio.h> #include <linux/pda_power.h> @@ -242,10 +244,43 @@ struct platform_device collie_locomo_device = { .resource = locomo_resources, }; +static struct gpio_keys_button collie_gpio_keys[] = { + { + .type = EV_PWR, + .code = KEY_RESERVED, + .gpio = COLLIE_GPIO_ON_KEY, + .desc = "On key", + .wakeup = 1, + .active_low = 1, + }, + { + .type = EV_PWR, + .code = KEY_WAKEUP, + .gpio = COLLIE_GPIO_WAKEUP, + .desc = "Sync", + .wakeup = 1, + .active_low = 1, + }, +}; + +static struct gpio_keys_platform_data collie_gpio_keys_data = { + .buttons = collie_gpio_keys, + .nbuttons = ARRAY_SIZE(collie_gpio_keys), +}; + +static struct platform_device collie_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &collie_gpio_keys_data, + }, +}; + static struct platform_device *devices[] __initdata = { &collie_locomo_device, &colliescoop_device, &collie_power_device, + &collie_gpio_keys_device, }; static struct mtd_partition collie_partitions[] = { diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c index b8f2b151539b..daa27c474c13 100644 --- a/arch/arm/mach-sa1100/h3100.c +++ b/arch/arm/mach-sa1100/h3100.c @@ -28,15 +28,35 @@ /* * helper for sa1100fb */ +static struct gpio h3100_lcd_gpio[] = { + { H3100_GPIO_LCD_3V_ON, GPIOF_OUT_INIT_LOW, "LCD 3V" }, + { H3XXX_EGPIO_LCD_ON, GPIOF_OUT_INIT_LOW, "LCD ON" }, +}; + +static bool h3100_lcd_request(void) +{ + static bool h3100_lcd_ok; + int rc; + + if (h3100_lcd_ok) + return true; + + rc = gpio_request_array(h3100_lcd_gpio, ARRAY_SIZE(h3100_lcd_gpio)); + if (rc) + pr_err("%s: can't request GPIOs\n", __func__); + else + h3100_lcd_ok = true; + + return h3100_lcd_ok; +} + static void h3100_lcd_power(int enable) { - if (!gpio_request(H3XXX_EGPIO_LCD_ON, "LCD ON")) { - gpio_set_value(H3100_GPIO_LCD_3V_ON, enable); - gpio_direction_output(H3XXX_EGPIO_LCD_ON, enable); - gpio_free(H3XXX_EGPIO_LCD_ON); - } else { - pr_err("%s: can't request H3XXX_EGPIO_LCD_ON\n", __func__); - } + if (!h3100_lcd_request()) + return; + + gpio_set_value(H3100_GPIO_LCD_3V_ON, enable); + gpio_set_value(H3XXX_EGPIO_LCD_ON, enable); } static struct sa1100fb_mach_info h3100_lcd_info = { @@ -69,6 +89,11 @@ static void __init h3100_map_io(void) /* * This turns the IRDA power on or off on the Compaq H3100 */ +static struct gpio h3100_irda_gpio[] = { + { H3100_GPIO_IR_ON, GPIOF_OUT_INIT_LOW, "IrDA power" }, + { H3100_GPIO_IR_FSEL, GPIOF_OUT_INIT_LOW, "IrDA fsel" }, +}; + static int h3100_irda_set_power(struct device *dev, unsigned int state) { gpio_set_value(H3100_GPIO_IR_ON, state); @@ -80,18 +105,27 @@ static void h3100_irda_set_speed(struct device *dev, unsigned int speed) gpio_set_value(H3100_GPIO_IR_FSEL, !(speed < 4000000)); } +static int h3100_irda_startup(struct device *dev) +{ + return gpio_request_array(h3100_irda_gpio, sizeof(h3100_irda_gpio)); +} + +static void h3100_irda_shutdown(struct device *dev) +{ + return gpio_free_array(h3100_irda_gpio, sizeof(h3100_irda_gpio)); +} + static struct irda_platform_data h3100_irda_data = { .set_power = h3100_irda_set_power, .set_speed = h3100_irda_set_speed, + .startup = h3100_irda_startup, + .shutdown = h3100_irda_shutdown, }; static struct gpio_default_state h3100_default_gpio[] = { - { H3100_GPIO_IR_ON, GPIO_MODE_OUT0, "IrDA power" }, - { H3100_GPIO_IR_FSEL, GPIO_MODE_OUT0, "IrDA fsel" }, { H3XXX_GPIO_COM_DCD, GPIO_MODE_IN, "COM DCD" }, { H3XXX_GPIO_COM_CTS, GPIO_MODE_IN, "COM CTS" }, { H3XXX_GPIO_COM_RTS, GPIO_MODE_OUT0, "COM RTS" }, - { H3100_GPIO_LCD_3V_ON, GPIO_MODE_OUT0, "LCD 3v" }, }; static void __init h3100_mach_init(void) diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index b8dc5bd22623..a663e7230141 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -28,35 +28,39 @@ /* * helper for sa1100fb */ +static struct gpio h3600_lcd_gpio[] = { + { H3XXX_EGPIO_LCD_ON, GPIOF_OUT_INIT_LOW, "LCD power" }, + { H3600_EGPIO_LCD_PCI, GPIOF_OUT_INIT_LOW, "LCD control" }, + { H3600_EGPIO_LCD_5V_ON, GPIOF_OUT_INIT_LOW, "LCD 5v" }, + { H3600_EGPIO_LVDD_ON, GPIOF_OUT_INIT_LOW, "LCD 9v/-6.5v" }, +}; + +static bool h3600_lcd_request(void) +{ + static bool h3600_lcd_ok; + int rc; + + if (h3600_lcd_ok) + return true; + + rc = gpio_request_array(h3600_lcd_gpio, ARRAY_SIZE(h3600_lcd_gpio)); + if (rc) + pr_err("%s: can't request GPIOs\n", __func__); + else + h3600_lcd_ok = true; + + return h3600_lcd_ok; +} + static void h3600_lcd_power(int enable) { - if (gpio_request(H3XXX_EGPIO_LCD_ON, "LCD power")) { - pr_err("%s: can't request H3XXX_EGPIO_LCD_ON\n", __func__); - goto err1; - } - if (gpio_request(H3600_EGPIO_LCD_PCI, "LCD control")) { - pr_err("%s: can't request H3XXX_EGPIO_LCD_PCI\n", __func__); - goto err2; - } - if (gpio_request(H3600_EGPIO_LCD_5V_ON, "LCD 5v")) { - pr_err("%s: can't request H3XXX_EGPIO_LCD_5V_ON\n", __func__); - goto err3; - } - if (gpio_request(H3600_EGPIO_LVDD_ON, "LCD 9v/-6.5v")) { - pr_err("%s: can't request H3600_EGPIO_LVDD_ON\n", __func__); - goto err4; - } + if (!h3600_lcd_request()) + return; gpio_direction_output(H3XXX_EGPIO_LCD_ON, enable); gpio_direction_output(H3600_EGPIO_LCD_PCI, enable); gpio_direction_output(H3600_EGPIO_LCD_5V_ON, enable); gpio_direction_output(H3600_EGPIO_LVDD_ON, enable); - - gpio_free(H3600_EGPIO_LVDD_ON); -err4: gpio_free(H3600_EGPIO_LCD_5V_ON); -err3: gpio_free(H3600_EGPIO_LCD_PCI); -err2: gpio_free(H3XXX_EGPIO_LCD_ON); -err1: return; } static const struct sa1100fb_rgb h3600_rgb_16 = { @@ -93,6 +97,11 @@ static void __init h3600_map_io(void) /* * This turns the IRDA power on or off on the Compaq H3600 */ +static struct gpio h3600_irda_gpio[] = { + { H3600_EGPIO_IR_ON, GPIOF_OUT_INIT_LOW, "IrDA power" }, + { H3600_EGPIO_IR_FSEL, GPIOF_OUT_INIT_LOW, "IrDA fsel" }, +}; + static int h3600_irda_set_power(struct device *dev, unsigned int state) { gpio_set_value(H3600_EGPIO_IR_ON, state); @@ -106,29 +115,12 @@ static void h3600_irda_set_speed(struct device *dev, unsigned int speed) static int h3600_irda_startup(struct device *dev) { - int err = gpio_request(H3600_EGPIO_IR_ON, "IrDA power"); - if (err) - goto err1; - err = gpio_direction_output(H3600_EGPIO_IR_ON, 0); - if (err) - goto err2; - err = gpio_request(H3600_EGPIO_IR_FSEL, "IrDA fsel"); - if (err) - goto err2; - err = gpio_direction_output(H3600_EGPIO_IR_FSEL, 0); - if (err) - goto err3; - return 0; - -err3: gpio_free(H3600_EGPIO_IR_FSEL); -err2: gpio_free(H3600_EGPIO_IR_ON); -err1: return err; + return gpio_request_array(h3600_irda_gpio, sizeof(h3600_irda_gpio)); } static void h3600_irda_shutdown(struct device *dev) { - gpio_free(H3600_EGPIO_IR_ON); - gpio_free(H3600_EGPIO_IR_FSEL); + return gpio_free_array(h3600_irda_gpio, sizeof(h3600_irda_gpio)); } static struct irda_platform_data h3600_irda_data = { diff --git a/arch/arm/mach-sa1100/include/mach/assabet.h b/arch/arm/mach-sa1100/include/mach/assabet.h index 307391488c22..c23fcdb047a5 100644 --- a/arch/arm/mach-sa1100/include/mach/assabet.h +++ b/arch/arm/mach-sa1100/include/mach/assabet.h @@ -39,8 +39,8 @@ extern unsigned long SCR_value; #define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */ #define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */ -#define ASSABET_BCR_GFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */ -#define ASSABET_BCR_CODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */ +#define ASSABET_BCR_NGFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */ +#define ASSABET_BCR_NCODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */ #define ASSABET_BCR_IRDA_FSEL (1<<3) /* IRDA Frequency select (0 = SIR, 1 = MIR/ FIR) */ #define ASSABET_BCR_IRDA_MD0 (1<<4) /* Range/Power select */ #define ASSABET_BCR_IRDA_MD1 (1<<5) /* Range/Power select */ @@ -69,6 +69,8 @@ extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set); #define ASSABET_BCR_frob(x,y) do { } while (0) #endif +extern void assabet_uda1341_reset(int set); + #define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x)) #define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0) |