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 v4.18-rc1 178 lines 4.0 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/slab.h> 11#include <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/platform_device.h> 14#include <linux/mfd/adp5520.h> 15#include <linux/gpio/driver.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 = gpiochip_get_data(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, ADP5520_GPIO_OUT, &reg_val); 38 else 39 adp5520_read(dev->master, ADP5520_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 = gpiochip_get_data(chip); 49 50 if (val) 51 adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]); 52 else 53 adp5520_clr_bits(dev->master, ADP5520_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 = gpiochip_get_data(chip); 60 61 clear_bit(off, &dev->output); 62 63 return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2, 64 dev->lut[off]); 65} 66 67static int adp5520_gpio_direction_output(struct gpio_chip *chip, 68 unsigned off, int val) 69{ 70 struct adp5520_gpio *dev; 71 int ret = 0; 72 dev = gpiochip_get_data(chip); 73 74 set_bit(off, &dev->output); 75 76 if (val) 77 ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, 78 dev->lut[off]); 79 else 80 ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, 81 dev->lut[off]); 82 83 ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2, 84 dev->lut[off]); 85 86 return ret; 87} 88 89static int adp5520_gpio_probe(struct platform_device *pdev) 90{ 91 struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); 92 struct adp5520_gpio *dev; 93 struct gpio_chip *gc; 94 int ret, i, gpios; 95 unsigned char ctl_mask = 0; 96 97 if (pdata == NULL) { 98 dev_err(&pdev->dev, "missing platform data\n"); 99 return -ENODEV; 100 } 101 102 if (pdev->id != ID_ADP5520) { 103 dev_err(&pdev->dev, "only ADP5520 supports GPIO\n"); 104 return -ENODEV; 105 } 106 107 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 108 if (dev == NULL) 109 return -ENOMEM; 110 111 dev->master = pdev->dev.parent; 112 113 for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++) 114 if (pdata->gpio_en_mask & (1 << i)) 115 dev->lut[gpios++] = 1 << i; 116 117 if (gpios < 1) { 118 ret = -EINVAL; 119 goto err; 120 } 121 122 gc = &dev->gpio_chip; 123 gc->direction_input = adp5520_gpio_direction_input; 124 gc->direction_output = adp5520_gpio_direction_output; 125 gc->get = adp5520_gpio_get_value; 126 gc->set = adp5520_gpio_set_value; 127 gc->can_sleep = true; 128 129 gc->base = pdata->gpio_start; 130 gc->ngpio = gpios; 131 gc->label = pdev->name; 132 gc->owner = THIS_MODULE; 133 134 ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1, 135 pdata->gpio_en_mask); 136 137 if (pdata->gpio_en_mask & ADP5520_GPIO_C3) 138 ctl_mask |= ADP5520_C3_MODE; 139 140 if (pdata->gpio_en_mask & ADP5520_GPIO_R3) 141 ctl_mask |= ADP5520_R3_MODE; 142 143 if (ctl_mask) 144 ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL, 145 ctl_mask); 146 147 ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP, 148 pdata->gpio_pullup_mask); 149 150 if (ret) { 151 dev_err(&pdev->dev, "failed to write\n"); 152 goto err; 153 } 154 155 ret = devm_gpiochip_add_data(&pdev->dev, &dev->gpio_chip, dev); 156 if (ret) 157 goto err; 158 159 platform_set_drvdata(pdev, dev); 160 return 0; 161 162err: 163 return ret; 164} 165 166static struct platform_driver adp5520_gpio_driver = { 167 .driver = { 168 .name = "adp5520-gpio", 169 }, 170 .probe = adp5520_gpio_probe, 171}; 172 173module_platform_driver(adp5520_gpio_driver); 174 175MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 176MODULE_DESCRIPTION("GPIO ADP5520 Driver"); 177MODULE_LICENSE("GPL"); 178MODULE_ALIAS("platform:adp5520-gpio");