rendered paste bodyFrom 57c08ae234f42060212c65235bb8d3f25ae17ade Mon Sep 17 00:00:00 2001From: Philipp Zabel <philipp.zabel@gmail.com>Date: Thu, 29 May 2008 12:24:32 +0200Subject: [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.cindex ef8a492..599f872 100644--- a/drivers/mfd/asic3.c+++ b/drivers/mfd/asic3.c@@ -20,11 +20,34 @@ #include <linux/kernel.h> #include <linux/irq.h> #include <linux/io.h>+#include <linux/gpio.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mfd/asic3.h> +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.hindex 4ab2162..f5d5df0 100644--- a/include/linux/mfd/asic3.h+++ b/include/linux/mfd/asic3.h@@ -16,16 +16,6 @@ #include <linux/types.h> -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