aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2008-07-25 04:45:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:29 -0400
commitf61be273d3699d174bc1438e6804f9f9e52bb932 (patch)
tree3d9940d725e2837168b8b072140b85b00c198896 /drivers/mfd
parent472dba7d117844c746be97db6be26c2810d79b62 (diff)
sm501: add gpiolib support
Add support for exporting the GPIOs on the SM501 via gpiolib. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Cc: Arnaud Patard <apatard@mandriva.com> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig8
-rw-r--r--drivers/mfd/sm501.c299
2 files changed, 255 insertions, 52 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9f93c29fed35..bac9e973ece0 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -19,6 +19,14 @@ config MFD_SM501
19 interface. The device may be connected by PCI or local bus with 19 interface. The device may be connected by PCI or local bus with
20 varying functions enabled. 20 varying functions enabled.
21 21
22config MFD_SM501_GPIO
23 bool "Export GPIO via GPIO layer"
24 depends on MFD_SM501 && HAVE_GPIO_LIB
25 ---help---
26 This option uses the gpio library layer to export the 64 GPIO
27 lines on the SM501. The platform data is used to supply the
28 base number for the first GPIO line to register.
29
22config MFD_ASIC3 30config MFD_ASIC3
23 bool "Support for Compaq ASIC3" 31 bool "Support for Compaq ASIC3"
24 depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM 32 depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 9296b2673b52..be8713908125 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -19,6 +19,7 @@
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/pci.h> 21#include <linux/pci.h>
22#include <linux/gpio.h>
22 23
23#include <linux/sm501.h> 24#include <linux/sm501.h>
24#include <linux/sm501-regs.h> 25#include <linux/sm501-regs.h>
@@ -31,10 +32,29 @@ struct sm501_device {
31 struct platform_device pdev; 32 struct platform_device pdev;
32}; 33};
33 34
35struct sm501_gpio;
36
37struct sm501_gpio_chip {
38 struct gpio_chip gpio;
39 struct sm501_gpio *ourgpio; /* to get back to parent. */
40 void __iomem *regbase;
41};
42
43struct sm501_gpio {
44 struct sm501_gpio_chip low;
45 struct sm501_gpio_chip high;
46 spinlock_t lock;
47
48 unsigned int registered : 1;
49 void __iomem *regs;
50 struct resource *regs_res;
51};
52
34struct sm501_devdata { 53struct sm501_devdata {
35 spinlock_t reg_lock; 54 spinlock_t reg_lock;
36 struct mutex clock_lock; 55 struct mutex clock_lock;
37 struct list_head devices; 56 struct list_head devices;
57 struct sm501_gpio gpio;
38 58
39 struct device *dev; 59 struct device *dev;
40 struct resource *io_res; 60 struct resource *io_res;
@@ -42,6 +62,7 @@ struct sm501_devdata {
42 struct resource *regs_claim; 62 struct resource *regs_claim;
43 struct sm501_platdata *platdata; 63 struct sm501_platdata *platdata;
44 64
65
45 unsigned int in_suspend; 66 unsigned int in_suspend;
46 unsigned long pm_misc; 67 unsigned long pm_misc;
47 68
@@ -52,6 +73,7 @@ struct sm501_devdata {
52 unsigned int rev; 73 unsigned int rev;
53}; 74};
54 75
76
55#define MHZ (1000 * 1000) 77#define MHZ (1000 * 1000)
56 78
57#ifdef DEBUG 79#ifdef DEBUG
@@ -276,58 +298,6 @@ unsigned long sm501_modify_reg(struct device *dev,
276 298
277EXPORT_SYMBOL_GPL(sm501_modify_reg); 299EXPORT_SYMBOL_GPL(sm501_modify_reg);
278 300
279unsigned long sm501_gpio_get(struct device *dev,
280 unsigned long gpio)
281{
282 struct sm501_devdata *sm = dev_get_drvdata(dev);
283 unsigned long result;
284 unsigned long reg;
285
286 reg = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
287 result = readl(sm->regs + reg);
288
289 result >>= (gpio & 31);
290 return result & 1UL;
291}
292
293EXPORT_SYMBOL_GPL(sm501_gpio_get);
294
295void sm501_gpio_set(struct device *dev,
296 unsigned long gpio,
297 unsigned int to,
298 unsigned int dir)
299{
300 struct sm501_devdata *sm = dev_get_drvdata(dev);
301
302 unsigned long bit = 1 << (gpio & 31);
303 unsigned long base;
304 unsigned long save;
305 unsigned long val;
306
307 base = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
308 base += SM501_GPIO;
309
310 spin_lock_irqsave(&sm->reg_lock, save);
311
312 val = readl(sm->regs + base) & ~bit;
313 if (to)
314 val |= bit;
315 writel(val, sm->regs + base);
316
317 val = readl(sm->regs + SM501_GPIO_DDR_LOW) & ~bit;
318 if (dir)
319 val |= bit;
320
321 writel(val, sm->regs + SM501_GPIO_DDR_LOW);
322 sm501_sync_regs(sm);
323
324 spin_unlock_irqrestore(&sm->reg_lock, save);
325
326}
327
328EXPORT_SYMBOL_GPL(sm501_gpio_set);
329
330
331/* sm501_unit_power 301/* sm501_unit_power
332 * 302 *
333 * alters the power active gate to set specific units on or off 303 * alters the power active gate to set specific units on or off
@@ -906,6 +876,226 @@ static int sm501_register_display(struct sm501_devdata *sm,
906 return sm501_register_device(sm, pdev); 876 return sm501_register_device(sm, pdev);
907} 877}
908 878
879#ifdef CONFIG_MFD_SM501_GPIO
880
881static inline struct sm501_gpio_chip *to_sm501_gpio(struct gpio_chip *gc)
882{
883 return container_of(gc, struct sm501_gpio_chip, gpio);
884}
885
886static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio)
887{
888 return container_of(gpio, struct sm501_devdata, gpio);
889}
890
891static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)
892
893{
894 struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip);
895 unsigned long result;
896
897 result = readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
898 result >>= offset;
899
900 return result & 1UL;
901}
902
903static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
904
905{
906 struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
907 struct sm501_gpio *smgpio = smchip->ourgpio;
908 unsigned long bit = 1 << offset;
909 void __iomem *regs = smchip->regbase;
910 unsigned long save;
911 unsigned long val;
912
913 dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n",
914 __func__, chip, offset);
915
916 spin_lock_irqsave(&smgpio->lock, save);
917
918 val = readl(regs + SM501_GPIO_DATA_LOW) & ~bit;
919 if (value)
920 val |= bit;
921 writel(val, regs);
922
923 sm501_sync_regs(sm501_gpio_to_dev(smgpio));
924 spin_unlock_irqrestore(&smgpio->lock, save);
925}
926
927static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
928{
929 struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
930 struct sm501_gpio *smgpio = smchip->ourgpio;
931 void __iomem *regs = smchip->regbase;
932 unsigned long bit = 1 << offset;
933 unsigned long save;
934 unsigned long ddr;
935
936 dev_info(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n",
937 __func__, chip, offset);
938
939 spin_lock_irqsave(&smgpio->lock, save);
940
941 ddr = readl(regs + SM501_GPIO_DDR_LOW);
942 writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
943
944 sm501_sync_regs(sm501_gpio_to_dev(smgpio));
945 spin_unlock_irqrestore(&smgpio->lock, save);
946
947 return 0;
948}
949
950static int sm501_gpio_output(struct gpio_chip *chip,
951 unsigned offset, int value)
952{
953 struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
954 struct sm501_gpio *smgpio = smchip->ourgpio;
955 unsigned long bit = 1 << offset;
956 void __iomem *regs = smchip->regbase;
957 unsigned long save;
958 unsigned long val;
959 unsigned long ddr;
960
961 dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d,%d)\n",
962 __func__, chip, offset, value);
963
964 spin_lock_irqsave(&smgpio->lock, save);
965
966 val = readl(regs + SM501_GPIO_DATA_LOW);
967 if (value)
968 val |= bit;
969 else
970 val &= ~bit;
971 writel(val, regs);
972
973 ddr = readl(regs + SM501_GPIO_DDR_LOW);
974 writel(ddr | bit, regs + SM501_GPIO_DDR_LOW);
975
976 sm501_sync_regs(sm501_gpio_to_dev(smgpio));
977 writel(val, regs + SM501_GPIO_DATA_LOW);
978
979 sm501_sync_regs(sm501_gpio_to_dev(smgpio));
980 spin_unlock_irqrestore(&smgpio->lock, save);
981
982 return 0;
983}
984
985static struct gpio_chip gpio_chip_template = {
986 .ngpio = 32,
987 .direction_input = sm501_gpio_input,
988 .direction_output = sm501_gpio_output,
989 .set = sm501_gpio_set,
990 .get = sm501_gpio_get,
991};
992
993static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm,
994 struct sm501_gpio *gpio,
995 struct sm501_gpio_chip *chip)
996{
997 struct sm501_platdata *pdata = sm->platdata;
998 struct gpio_chip *gchip = &chip->gpio;
999 unsigned base = pdata->gpio_base;
1000
1001 memcpy(chip, &gpio_chip_template, sizeof(struct gpio_chip));
1002
1003 if (chip == &gpio->high) {
1004 base += 32;
1005 chip->regbase = gpio->regs + SM501_GPIO_DATA_HIGH;
1006 gchip->label = "SM501-HIGH";
1007 } else {
1008 chip->regbase = gpio->regs + SM501_GPIO_DATA_LOW;
1009 gchip->label = "SM501-LOW";
1010 }
1011
1012 gchip->base = base;
1013 chip->ourgpio = gpio;
1014
1015 return gpiochip_add(gchip);
1016}
1017
1018static int sm501_register_gpio(struct sm501_devdata *sm)
1019{
1020 struct sm501_gpio *gpio = &sm->gpio;
1021 resource_size_t iobase = sm->io_res->start + SM501_GPIO;
1022 int ret;
1023 int tmp;
1024
1025 dev_dbg(sm->dev, "registering gpio block %08llx\n",
1026 (unsigned long long)iobase);
1027
1028 spin_lock_init(&gpio->lock);
1029
1030 gpio->regs_res = request_mem_region(iobase, 0x20, "sm501-gpio");
1031 if (gpio->regs_res == NULL) {
1032 dev_err(sm->dev, "gpio: failed to request region\n");
1033 return -ENXIO;
1034 }
1035
1036 gpio->regs = ioremap(iobase, 0x20);
1037 if (gpio->regs == NULL) {
1038 dev_err(sm->dev, "gpio: failed to remap registers\n");
1039 ret = -ENXIO;
1040 goto err_mapped;
1041 }
1042
1043 /* Register both our chips. */
1044
1045 ret = sm501_gpio_register_chip(sm, gpio, &gpio->low);
1046 if (ret) {
1047 dev_err(sm->dev, "failed to add low chip\n");
1048 goto err_mapped;
1049 }
1050
1051 ret = sm501_gpio_register_chip(sm, gpio, &gpio->high);
1052 if (ret) {
1053 dev_err(sm->dev, "failed to add high chip\n");
1054 goto err_low_chip;
1055 }
1056
1057 gpio->registered = 1;
1058
1059 return 0;
1060
1061 err_low_chip:
1062 tmp = gpiochip_remove(&gpio->low.gpio);
1063 if (tmp) {
1064 dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
1065 return ret;
1066 }
1067
1068 err_mapped:
1069 release_resource(gpio->regs_res);
1070 kfree(gpio->regs_res);
1071
1072 return ret;
1073}
1074
1075static void sm501_gpio_remove(struct sm501_devdata *sm)
1076{
1077 int ret;
1078
1079 ret = gpiochip_remove(&sm->gpio.low.gpio);
1080 if (ret)
1081 dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
1082
1083 ret = gpiochip_remove(&sm->gpio.high.gpio);
1084 if (ret)
1085 dev_err(sm->dev, "cannot remove high chip, cannot tidy up\n");
1086}
1087
1088#else
1089static int sm501_register_gpio(struct sm501_devdata *sm)
1090{
1091 return 0;
1092}
1093
1094static void sm501_gpio_remove(struct sm501_devdata *sm)
1095{
1096}
1097#endif
1098
909/* sm501_dbg_regs 1099/* sm501_dbg_regs
910 * 1100 *
911 * Debug attribute to attach to parent device to show core registers 1101 * Debug attribute to attach to parent device to show core registers
@@ -1059,6 +1249,8 @@ static int sm501_init_dev(struct sm501_devdata *sm)
1059 sm501_register_usbhost(sm, &mem_avail); 1249 sm501_register_usbhost(sm, &mem_avail);
1060 if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1)) 1250 if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1))
1061 sm501_register_uart(sm, idata->devices); 1251 sm501_register_uart(sm, idata->devices);
1252 if (idata->devices & SM501_USE_GPIO)
1253 sm501_register_gpio(sm);
1062 } 1254 }
1063 1255
1064 ret = sm501_check_clocks(sm); 1256 ret = sm501_check_clocks(sm);
@@ -1366,6 +1558,9 @@ static void sm501_dev_remove(struct sm501_devdata *sm)
1366 sm501_remove_sub(sm, smdev); 1558 sm501_remove_sub(sm, smdev);
1367 1559
1368 device_remove_file(sm->dev, &dev_attr_dbg_regs); 1560 device_remove_file(sm->dev, &dev_attr_dbg_regs);
1561
1562 if (sm->gpio.registered)
1563 sm501_gpio_remove(sm);
1369} 1564}
1370 1565
1371static void sm501_pci_remove(struct pci_dev *dev) 1566static void sm501_pci_remove(struct pci_dev *dev)