aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/sm501.c
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/sm501.c
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/sm501.c')
-rw-r--r--drivers/mfd/sm501.c299
1 files changed, 247 insertions, 52 deletions
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)