From 57c08ae234f42060212c65235bb8d3f25ae17ade Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 29 May 2008 12:24:32 +0200 Subject: [PATCH] WIP: ASIC3: GPIO API support --- drivers/mfd/asic3.c | 145 +++++++++++++++++++++++++++++++++++++++++---- include/linux/mfd/asic3.h | 14 +---- 2 files changed, 134 insertions(+), 25 deletions(-) diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index ef8a492..599f872 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -20,11 +20,34 @@ #include #include #include +#include #include #include #include +struct asic3; + +struct asic3_gpio_chip { + struct asic3 *asic; + unsigned int base; + struct gpio_chip chip; +}; + +struct asic3 { + void __iomem *mapping; + unsigned int bus_shift; + unsigned int irq_nr; + unsigned int irq_base; + spinlock_t lock; + u16 irq_bothedge[4]; + struct asic3_gpio_chip agpio[4]; + struct device *dev; +}; + +int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio); +void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); + static inline void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) { @@ -394,6 +417,46 @@ static void asic3_set_gpio(struct asic3 *asic, unsigned int base, asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \ } while (0) +/* GPIO API */ +static int asic3_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct asic3_gpio_chip *agpio; + struct asic3 *asic; + unsigned long flags; + int val; + + agpio = container_of(chip, struct asic3_gpio_chip, chip); + asic = agpio->asic; + + spin_lock_irqsave(&asic->lock, flags); + val = asic3_read_register(asic, agpio->base + ASIC3_GPIO_Direction); + val &= ~(1 << offset); + asic3_write_register(asic, agpio->base + ASIC3_GPIO_Direction, val); + spin_unlock_irqrestore(&asic->lock, flags); + + return 0; +} + +static int asic3_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct asic3_gpio_chip *agpio; + struct asic3 *asic; + unsigned long flags; + int val; + + agpio = container_of(chip, struct asic3_gpio_chip, chip); + asic = agpio->asic; + + spin_lock_irqsave(&asic->lock, flags); + val = asic3_read_register(asic, agpio->base + ASIC3_GPIO_Direction); + val |= (1 << offset); + asic3_write_register(asic, agpio->base + ASIC3_GPIO_Direction, val); + spin_unlock_irqrestore(&asic->lock, flags); + + return 0; +} + int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio) { u32 mask = ASIC3_GPIO_bit(gpio); @@ -415,6 +478,19 @@ int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio) } EXPORT_SYMBOL(asic3_gpio_get_value); +/* GPIO API */ +static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct asic3_gpio_chip *agpio; + struct asic3 *asic; + + agpio = container_of(chip, struct asic3_gpio_chip, chip); + asic = agpio->asic; + + return asic3_get_gpio(asic, agpio->base, + ASIC3_GPIO_Status) & (1 << offset); +} + void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val) { u32 mask = ASIC3_GPIO_bit(gpio); @@ -443,10 +519,33 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val) } EXPORT_SYMBOL(asic3_gpio_set_value); +/* GPIO API */ +static void asic3_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct asic3_gpio_chip *agpio; + struct asic3 *asic; + unsigned long flags; + int val; + + agpio = container_of(chip, struct asic3_gpio_chip, chip); + asic = agpio->asic; + + spin_lock_irqsave(&asic->lock, flags); + val = asic3_read_register(asic, agpio->base + ASIC3_GPIO_Out); + if (value) + val |= (1 << offset); + else + val &= ~(1 << offset); + asic3_write_register(asic, agpio->base + ASIC3_GPIO_Out, val); + spin_unlock_irqrestore(&asic->lock, flags); +} + static int asic3_gpio_probe(struct platform_device *pdev) { struct asic3_platform_data *pdata = pdev->dev.platform_data; struct asic3 *asic = platform_get_drvdata(pdev); + struct gpio_chip *chip; + int bank; asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, Mask), 0xffff); asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, Mask), 0xffff); @@ -458,18 +557,34 @@ static int asic3_gpio_probe(struct platform_device *pdev) asic3_set_gpio_c(asic, SleepMask, 0xffff, 0xffff); asic3_set_gpio_d(asic, SleepMask, 0xffff, 0xffff); - if (pdata) { - asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init); - asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir); - asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata, - sleep_mask); - asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out); - asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata, - batt_fault_out); - asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata, - sleep_conf); - asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata, - alt_function); + if (!pdata) + return 0; + + asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init); + asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir); + asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata, + sleep_mask); + asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out); + asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata, + batt_fault_out); + asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata, + sleep_conf); + asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata, + alt_function); + + for (bank = 0; bank < 4; bank++) { + asic->agpio[bank].asic = asic; + asic->agpio[bank].base = ASIC3_GPIO_A_Base + + bank * ASIC3_GPIO_Base_INCR; + chip = &(asic->agpio[bank].chip); + chip->label = "asic3"; + chip->get = asic3_gpio_get; + chip->set = asic3_gpio_set; + chip->direction_input = asic3_gpio_direction_input; + chip->direction_output = asic3_gpio_direction_output; + chip->base = pdata->gpio_base + 16 * bank; + chip->ngpio = 16; + gpiochip_add(chip); } return 0; @@ -477,6 +592,12 @@ static int asic3_gpio_probe(struct platform_device *pdev) static void asic3_gpio_remove(struct platform_device *pdev) { + struct asic3 *asic = platform_get_drvdata(pdev); + int bank; + + for (bank = 0; bank < 4; bank++) + gpiochip_remove(&(asic->agpio[bank].chip)); + return; } diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h index 4ab2162..f5d5df0 100644 --- a/include/linux/mfd/asic3.h +++ b/include/linux/mfd/asic3.h @@ -16,16 +16,6 @@ #include -struct asic3 { - void __iomem *mapping; - unsigned int bus_shift; - unsigned int irq_nr; - unsigned int irq_base; - spinlock_t lock; - u16 irq_bothedge[4]; - struct device *dev; -}; - struct asic3_platform_data { struct { u32 dir; @@ -40,14 +30,12 @@ struct asic3_platform_data { unsigned int bus_shift; unsigned int irq_base; + unsigned int gpio_base; struct platform_device **children; unsigned int n_children; }; -int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio); -void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); - #define ASIC3_NUM_GPIO_BANKS 4 #define ASIC3_GPIOS_PER_BANK 16 #define ASIC3_NUM_GPIOS 64 -- 1.5.5.3