Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.32-rc3 206 lines 4.6 kB view raw
1/* 2 * GPIO driver for Analog Devices ADP5520 MFD PMICs 3 * 4 * Copyright 2009 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later. 7 */ 8 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/platform_device.h> 13#include <linux/mfd/adp5520.h> 14 15#include <linux/gpio.h> 16 17struct adp5520_gpio { 18 struct device *master; 19 struct gpio_chip gpio_chip; 20 unsigned char lut[ADP5520_MAXGPIOS]; 21 unsigned long output; 22}; 23 24static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off) 25{ 26 struct adp5520_gpio *dev; 27 uint8_t reg_val; 28 29 dev = container_of(chip, struct adp5520_gpio, gpio_chip); 30 31 /* 32 * There are dedicated registers for GPIO IN/OUT. 33 * Make sure we return the right value, even when configured as output 34 */ 35 36 if (test_bit(off, &dev->output)) 37 adp5520_read(dev->master, GPIO_OUT, &reg_val); 38 else 39 adp5520_read(dev->master, GPIO_IN, &reg_val); 40 41 return !!(reg_val & dev->lut[off]); 42} 43 44static void adp5520_gpio_set_value(struct gpio_chip *chip, 45 unsigned off, int val) 46{ 47 struct adp5520_gpio *dev; 48 dev = container_of(chip, struct adp5520_gpio, gpio_chip); 49 50 if (val) 51 adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]); 52 else 53 adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]); 54} 55 56static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off) 57{ 58 struct adp5520_gpio *dev; 59 dev = container_of(chip, struct adp5520_gpio, gpio_chip); 60 61 clear_bit(off, &dev->output); 62 63 return adp5520_clr_bits(dev->master, GPIO_CFG_2, dev->lut[off]); 64} 65 66static int adp5520_gpio_direction_output(struct gpio_chip *chip, 67 unsigned off, int val) 68{ 69 struct adp5520_gpio *dev; 70 int ret = 0; 71 dev = container_of(chip, struct adp5520_gpio, gpio_chip); 72 73 set_bit(off, &dev->output); 74 75 if (val) 76 ret |= adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]); 77 else 78 ret |= adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]); 79 80 ret |= adp5520_set_bits(dev->master, GPIO_CFG_2, dev->lut[off]); 81 82 return ret; 83} 84 85static int __devinit adp5520_gpio_probe(struct platform_device *pdev) 86{ 87 struct adp5520_gpio_platfrom_data *pdata = pdev->dev.platform_data; 88 struct adp5520_gpio *dev; 89 struct gpio_chip *gc; 90 int ret, i, gpios; 91 unsigned char ctl_mask = 0; 92 93 if (pdata == NULL) { 94 dev_err(&pdev->dev, "missing platform data\n"); 95 return -ENODEV; 96 } 97 98 if (pdev->id != ID_ADP5520) { 99 dev_err(&pdev->dev, "only ADP5520 supports GPIO\n"); 100 return -ENODEV; 101 } 102 103 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 104 if (dev == NULL) { 105 dev_err(&pdev->dev, "failed to alloc memory\n"); 106 return -ENOMEM; 107 } 108 109 dev->master = pdev->dev.parent; 110 111 for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++) 112 if (pdata->gpio_en_mask & (1 << i)) 113 dev->lut[gpios++] = 1 << i; 114 115 if (gpios < 1) { 116 ret = -EINVAL; 117 goto err; 118 } 119 120 gc = &dev->gpio_chip; 121 gc->direction_input = adp5520_gpio_direction_input; 122 gc->direction_output = adp5520_gpio_direction_output; 123 gc->get = adp5520_gpio_get_value; 124 gc->set = adp5520_gpio_set_value; 125 gc->can_sleep = 1; 126 127 gc->base = pdata->gpio_start; 128 gc->ngpio = gpios; 129 gc->label = pdev->name; 130 gc->owner = THIS_MODULE; 131 132 ret = adp5520_clr_bits(dev->master, GPIO_CFG_1, 133 pdata->gpio_en_mask); 134 135 if (pdata->gpio_en_mask & GPIO_C3) 136 ctl_mask |= C3_MODE; 137 138 if (pdata->gpio_en_mask & GPIO_R3) 139 ctl_mask |= R3_MODE; 140 141 if (ctl_mask) 142 ret = adp5520_set_bits(dev->master, LED_CONTROL, 143 ctl_mask); 144 145 ret |= adp5520_set_bits(dev->master, GPIO_PULLUP, 146 pdata->gpio_pullup_mask); 147 148 if (ret) { 149 dev_err(&pdev->dev, "failed to write\n"); 150 goto err; 151 } 152 153 ret = gpiochip_add(&dev->gpio_chip); 154 if (ret) 155 goto err; 156 157 platform_set_drvdata(pdev, dev); 158 return 0; 159 160err: 161 kfree(dev); 162 return ret; 163} 164 165static int __devexit adp5520_gpio_remove(struct platform_device *pdev) 166{ 167 struct adp5520_gpio *dev; 168 int ret; 169 170 dev = platform_get_drvdata(pdev); 171 ret = gpiochip_remove(&dev->gpio_chip); 172 if (ret) { 173 dev_err(&pdev->dev, "%s failed, %d\n", 174 "gpiochip_remove()", ret); 175 return ret; 176 } 177 178 kfree(dev); 179 return 0; 180} 181 182static struct platform_driver adp5520_gpio_driver = { 183 .driver = { 184 .name = "adp5520-gpio", 185 .owner = THIS_MODULE, 186 }, 187 .probe = adp5520_gpio_probe, 188 .remove = __devexit_p(adp5520_gpio_remove), 189}; 190 191static int __init adp5520_gpio_init(void) 192{ 193 return platform_driver_register(&adp5520_gpio_driver); 194} 195module_init(adp5520_gpio_init); 196 197static void __exit adp5520_gpio_exit(void) 198{ 199 platform_driver_unregister(&adp5520_gpio_driver); 200} 201module_exit(adp5520_gpio_exit); 202 203MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 204MODULE_DESCRIPTION("GPIO ADP5520 Driver"); 205MODULE_LICENSE("GPL"); 206MODULE_ALIAS("platform:adp5520-gpio");