diff options
Diffstat (limited to 'arch/arm/mach-sa1100/assabet.c')
| -rw-r--r-- | arch/arm/mach-sa1100/assabet.c | 379 |
1 files changed, 180 insertions, 199 deletions
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index d28ecb9ef172..2b833aa0212b 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -1,20 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/mach-sa1100/assabet.c * * Author: Nicolas Pitre * * This file contains all Assabet-specific tweaks. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/gpio-reg.h> +#include <linux/gpio/machine.h> +#include <linux/gpio_keys.h> #include <linux/ioport.h> #include <linux/platform_data/sa11x0-serial.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/serial_core.h> #include <linux/platform_device.h> #include <linux/mfd/ucb1x00.h> @@ -32,12 +35,10 @@ #include <asm/setup.h> #include <asm/page.h> #include <asm/pgtable-hwdef.h> -#include <asm/pgtable.h> #include <asm/tlbflush.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> -#include <linux/platform_data/irda-sa11x0.h> #include <asm/mach/map.h> #include <mach/assabet.h> #include <linux/platform_data/mfd-mcp-sa11x0.h> @@ -61,20 +62,43 @@ unsigned long SCR_value = ASSABET_SCR_INIT; EXPORT_SYMBOL(SCR_value); -static unsigned long BCR_value = ASSABET_BCR_DB1110; +static struct gpio_chip *assabet_bcr_gc; + +static const char *assabet_names[] = { + "cf_pwr", "cf_gfx_reset", "nsoft_reset", "irda_fsel", + "irda_md0", "irda_md1", "stereo_loopback", "ncf_bus_on", + "audio_pwr_on", "light_pwr_on", "lcd16data", "lcd_pwr_on", + "rs232_on", "nred_led", "ngreen_led", "vib_on", + "com_dtr", "com_rts", "radio_wake_mod", "i2c_enab", + "tvir_enab", "qmute", "radio_pwr_on", "spkr_off", + "rs232_valid", "com_dcd", "com_cts", "com_dsr", + "radio_cts", "radio_dsr", "radio_dcd", "radio_ri", +}; +/* The old deprecated interface */ void ASSABET_BCR_frob(unsigned int mask, unsigned int val) { - unsigned long flags; + unsigned long m = mask, v = val; - local_irq_save(flags); - BCR_value = (BCR_value & ~mask) | val; - ASSABET_BCR = BCR_value; - local_irq_restore(flags); + assabet_bcr_gc->set_multiple(assabet_bcr_gc, &m, &v); } - EXPORT_SYMBOL(ASSABET_BCR_frob); +static void __init assabet_init_gpio(void __iomem *reg, u32 def_val) +{ + struct gpio_chip *gc; + + writel_relaxed(def_val, reg); + + gc = gpio_reg_init(NULL, reg, -1, 32, "assabet", 0xff000000, def_val, + assabet_names, NULL, NULL); + + if (IS_ERR(gc)) + return; + + assabet_bcr_gc = gc; +} + /* * The codec reset goes to three devices, so we need to release * the rest when any one of these requests it. However, that @@ -146,7 +170,7 @@ static void adv7171_write(unsigned reg, unsigned val) unsigned gpdr = GPDR; unsigned gplr = GPLR; - ASSABET_BCR = BCR_value | ASSABET_BCR_AUDIO_ON; + ASSABET_BCR_frob(ASSABET_BCR_AUDIO_ON, ASSABET_BCR_AUDIO_ON); udelay(100); GPCR = SDA | SCK | MOD; /* clear L3 mode to ensure UDA1341 doesn't respond */ @@ -273,38 +297,6 @@ static struct resource assabet_flash_resources[] = { }; -/* - * Assabet IrDA support code. - */ - -static int assabet_irda_set_power(struct device *dev, unsigned int state) -{ - static unsigned int bcr_state[4] = { - ASSABET_BCR_IRDA_MD0, - ASSABET_BCR_IRDA_MD1|ASSABET_BCR_IRDA_MD0, - ASSABET_BCR_IRDA_MD1, - 0 - }; - - if (state < 4) - ASSABET_BCR_frob(ASSABET_BCR_IRDA_MD1 | ASSABET_BCR_IRDA_MD0, - bcr_state[state]); - return 0; -} - -static void assabet_irda_set_speed(struct device *dev, unsigned int speed) -{ - if (speed < 4000000) - ASSABET_BCR_clear(ASSABET_BCR_IRDA_FSEL); - else - ASSABET_BCR_set(ASSABET_BCR_IRDA_FSEL); -} - -static struct irda_platform_data assabet_irda_data = { - .set_power = assabet_irda_set_power, - .set_speed = assabet_irda_set_speed, -}; - static struct ucb1x00_plat_data assabet_ucb1x00_data = { .reset = assabet_ucb1x00_reset, .gpio_base = -1, @@ -419,6 +411,109 @@ static struct resource neponset_resources[] = { }; #endif +static struct gpiod_lookup_table assabet_cf_gpio_table = { + .dev_id = "sa11x0-pcmcia.1", + .table = { + GPIO_LOOKUP("gpio", 21, "ready", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio", 22, "detect", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("gpio", 24, "bvd2", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio", 25, "bvd1", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("assabet", 1, "reset", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("assabet", 7, "bus-enable", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct regulator_consumer_supply assabet_cf_vcc_consumers[] = { + REGULATOR_SUPPLY("vcc", "sa11x0-pcmcia.1"), +}; + +static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = { + .supply_name = "cf-power", + .microvolts = 3300000, +}; + +static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + GPIO_LOOKUP("assabet", 0, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table assabet_leds_gpio_table = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP("assabet", 13, NULL, GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 14, NULL, GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpio_led assabet_leds[] __initdata = { + { + .name = "assabet:red", + .default_trigger = "cpu0", + .default_state = LEDS_GPIO_DEFSTATE_KEEP, + }, { + .name = "assabet:green", + .default_trigger = "heartbeat", + .default_state = LEDS_GPIO_DEFSTATE_KEEP, + }, +}; + +static const struct gpio_led_platform_data assabet_leds_pdata __initconst = { + .num_leds = ARRAY_SIZE(assabet_leds), + .leds = assabet_leds, +}; + +static struct gpio_keys_button assabet_keys_buttons[] = { + { + .gpio = 0, + .irq = IRQ_GPIO0, + .desc = "gpio0", + .wakeup = 1, + .can_disable = 1, + .debounce_interval = 5, + }, { + .gpio = 1, + .irq = IRQ_GPIO1, + .desc = "gpio1", + .wakeup = 1, + .can_disable = 1, + .debounce_interval = 5, + }, +}; + +static const struct gpio_keys_platform_data assabet_keys_pdata = { + .buttons = assabet_keys_buttons, + .nbuttons = ARRAY_SIZE(assabet_keys_buttons), + .rep = 0, +}; + +static struct gpiod_lookup_table assabet_uart1_gpio_table = { + .dev_id = "sa11x0-uart.1", + .table = { + GPIO_LOOKUP("assabet", 16, "dtr", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 17, "rts", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 25, "dcd", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 26, "cts", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 27, "dsr", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table assabet_uart3_gpio_table = { + .dev_id = "sa11x0-uart.3", + .table = { + GPIO_LOOKUP("assabet", 28, "cts", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 29, "dsr", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 30, "dcd", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("assabet", 31, "rng", GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init assabet_init(void) { /* @@ -457,14 +552,6 @@ static void __init assabet_init(void) sa11x0_ppc_configure_mcp(); if (machine_has_neponset()) { - /* - * Angel sets this, but other bootloaders may not. - * - * This must precede any driver calls to BCR_set() - * or BCR_clear(). - */ - ASSABET_BCR = BCR_value = ASSABET_BCR_DB1111; - #ifndef CONFIG_ASSABET_NEPONSET printk( "Warning: Neponset detected but full support " "hasn't been configured in the kernel\n" ); @@ -472,8 +559,26 @@ static void __init assabet_init(void) platform_device_register_simple("neponset", 0, neponset_resources, ARRAY_SIZE(neponset_resources)); #endif + } else { + gpiod_add_lookup_table(&assabet_uart1_gpio_table); + gpiod_add_lookup_table(&assabet_uart3_gpio_table); + gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table); + + sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata, + assabet_cf_vcc_consumers, + ARRAY_SIZE(assabet_cf_vcc_consumers), + true); + } + platform_device_register_resndata(NULL, "gpio-keys", 0, + NULL, 0, + &assabet_keys_pdata, + sizeof(assabet_keys_pdata)); + + gpiod_add_lookup_table(&assabet_leds_gpio_table); + gpio_led_register_device(-1, &assabet_leds_pdata); + #ifndef ASSABET_PAL_VIDEO sa11x0_register_lcd(&lq039q2ds54_info); #else @@ -481,8 +586,10 @@ static void __init assabet_init(void) #endif sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources, ARRAY_SIZE(assabet_flash_resources)); - sa11x0_register_irda(&assabet_irda_data); sa11x0_register_mcp(&assabet_mcp_data); + + if (!machine_has_neponset()) + sa11x0_register_pcmcia(1, &assabet_cf_gpio_table); } /* @@ -498,7 +605,7 @@ static void __init map_sa1100_gpio_regs( void ) int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO); pmd_t *pmd; - pmd = pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt); + pmd = pmd_off_k(virt); *pmd = __pmd(phys | prot); flush_pmd_entry(pmd); } @@ -518,7 +625,7 @@ static void __init map_sa1100_gpio_regs( void ) */ static void __init get_assabet_scr(void) { - unsigned long uninitialized_var(scr), i; + unsigned long scr, i; GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ @@ -546,74 +653,13 @@ static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate) { if (port->mapbase == _Ser1UTCR0) { if (state) - ASSABET_BCR_clear(ASSABET_BCR_RS232EN | - ASSABET_BCR_COM_RTS | - ASSABET_BCR_COM_DTR); - else - ASSABET_BCR_set(ASSABET_BCR_RS232EN | - ASSABET_BCR_COM_RTS | - ASSABET_BCR_COM_DTR); - } -} - -/* - * Assabet uses COM_RTS and COM_DTR for both UART1 (com port) - * and UART3 (radio module). We only handle them for UART1 here. - */ -static void assabet_set_mctrl(struct uart_port *port, u_int mctrl) -{ - if (port->mapbase == _Ser1UTCR0) { - u_int set = 0, clear = 0; - - if (mctrl & TIOCM_RTS) - clear |= ASSABET_BCR_COM_RTS; + ASSABET_BCR_clear(ASSABET_BCR_RS232EN); else - set |= ASSABET_BCR_COM_RTS; - - if (mctrl & TIOCM_DTR) - clear |= ASSABET_BCR_COM_DTR; - else - set |= ASSABET_BCR_COM_DTR; - - ASSABET_BCR_clear(clear); - ASSABET_BCR_set(set); + ASSABET_BCR_set(ASSABET_BCR_RS232EN); } } -static u_int assabet_get_mctrl(struct uart_port *port) -{ - u_int ret = 0; - u_int bsr = ASSABET_BSR; - - /* need 2 reads to read current value */ - bsr = ASSABET_BSR; - - if (port->mapbase == _Ser1UTCR0) { - if (bsr & ASSABET_BSR_COM_DCD) - ret |= TIOCM_CD; - if (bsr & ASSABET_BSR_COM_CTS) - ret |= TIOCM_CTS; - if (bsr & ASSABET_BSR_COM_DSR) - ret |= TIOCM_DSR; - } else if (port->mapbase == _Ser3UTCR0) { - if (bsr & ASSABET_BSR_RAD_DCD) - ret |= TIOCM_CD; - if (bsr & ASSABET_BSR_RAD_CTS) - ret |= TIOCM_CTS; - if (bsr & ASSABET_BSR_RAD_DSR) - ret |= TIOCM_DSR; - if (bsr & ASSABET_BSR_RAD_RI) - ret |= TIOCM_RI; - } else { - ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; - } - - return ret; -} - static struct sa1100_port_fns assabet_port_fns __initdata = { - .set_mctrl = assabet_set_mctrl, - .get_mctrl = assabet_get_mctrl, .pm = assabet_uart_pm, }; @@ -664,96 +710,31 @@ static void __init assabet_map_io(void) sa1100_register_uart(2, 3); } -/* LEDs */ -#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) -struct assabet_led { - struct led_classdev cdev; - u32 mask; -}; - -/* - * The triggers lines up below will only be used if the - * LED triggers are compiled in. - */ -static const struct { - const char *name; - const char *trigger; -} assabet_leds[] = { - { "assabet:red", "cpu0",}, - { "assabet:green", "heartbeat", }, -}; - -/* - * The LED control in Assabet is reversed: - * - setting bit means turn off LED - * - clearing bit means turn on LED - */ -static void assabet_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - struct assabet_led *led = container_of(cdev, - struct assabet_led, cdev); - - if (b != LED_OFF) - ASSABET_BCR_clear(led->mask); - else - ASSABET_BCR_set(led->mask); -} - -static enum led_brightness assabet_led_get(struct led_classdev *cdev) +static void __init assabet_init_irq(void) { - struct assabet_led *led = container_of(cdev, - struct assabet_led, cdev); - - return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL; -} - -static int __init assabet_leds_init(void) -{ - int i; - - if (!machine_is_assabet()) - return -ENODEV; - - for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) { - struct assabet_led *led; + u32 def_val; - led = kzalloc(sizeof(*led), GFP_KERNEL); - if (!led) - break; + sa1100_init_irq(); - led->cdev.name = assabet_leds[i].name; - led->cdev.brightness_set = assabet_led_set; - led->cdev.brightness_get = assabet_led_get; - led->cdev.default_trigger = assabet_leds[i].trigger; - - if (!i) - led->mask = ASSABET_BCR_LED_RED; - else - led->mask = ASSABET_BCR_LED_GREEN; - - if (led_classdev_register(NULL, &led->cdev) < 0) { - kfree(led); - break; - } - } + if (machine_has_neponset()) + def_val = ASSABET_BCR_DB1111; + else + def_val = ASSABET_BCR_DB1110; - return 0; + /* + * Angel sets this, but other bootloaders may not. + * + * This must precede any driver calls to BCR_set() or BCR_clear(). + */ + assabet_init_gpio((void *)&ASSABET_BCR, def_val); } -/* - * Since we may have triggers on any subsystem, defer registration - * until after subsystem_init. - */ -fs_initcall(assabet_leds_init); -#endif - MACHINE_START(ASSABET, "Intel-Assabet") .atag_offset = 0x100, .fixup = fixup_assabet, .map_io = assabet_map_io, .nr_irqs = SA1100_NR_IRQS, - .init_irq = sa1100_init_irq, + .init_irq = assabet_init_irq, .init_time = sa1100_timer_init, .init_machine = assabet_init, .init_late = sa11x0_init_late, |
