1 /* 2 * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ 3 * Keerthy <j-keerthy@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 10 * kind, whether expressed or implied; without even the implied warranty 11 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License version 2 for more details. 13 * 14 * Based on the LP873X driver 15 */ 16 17 #include <linux/gpio/driver.h> 18 #include <linux/module.h> 19 #include <linux/platform_device.h> 20 #include <linux/regmap.h> 21 22 #include <linux/mfd/lp87565.h> 23 24 struct lp87565_gpio { 25 struct gpio_chip chip; 26 struct regmap *map; 27 }; 28 29 static int lp87565_gpio_get_direction(struct gpio_chip *chip, 30 unsigned int offset) 31 { 32 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 33 int ret, val; 34 35 ret = regmap_read(gpio->map, LP87565_REG_GPIO_CONFIG, &val); 36 if (ret < 0) 37 return ret; 38 39 return !(val & BIT(offset)); 40 } 41 42 static int lp87565_gpio_direction_input(struct gpio_chip *chip, 43 unsigned int offset) 44 { 45 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 46 47 return regmap_update_bits(gpio->map, 48 LP87565_REG_GPIO_CONFIG, 49 BIT(offset), 0); 50 } 51 52 static int lp87565_gpio_direction_output(struct gpio_chip *chip, 53 unsigned int offset, int value) 54 { 55 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 56 57 return regmap_update_bits(gpio->map, 58 LP87565_REG_GPIO_CONFIG, 59 BIT(offset), !value ? BIT(offset) : 0); 60 } 61 62 static int lp87565_gpio_get(struct gpio_chip *chip, unsigned int offset) 63 { 64 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 65 int ret, val; 66 67 ret = regmap_read(gpio->map, LP87565_REG_GPIO_IN, &val); 68 if (ret < 0) 69 return ret; 70 71 return !!(val & BIT(offset)); 72 } 73 74 static void lp87565_gpio_set(struct gpio_chip *chip, unsigned int offset, 75 int value) 76 { 77 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 78 79 regmap_update_bits(gpio->map, LP87565_REG_GPIO_OUT, 80 BIT(offset), value ? BIT(offset) : 0); 81 } 82 83 static int lp87565_gpio_request(struct gpio_chip *gc, unsigned int offset) 84 { 85 struct lp87565_gpio *gpio = gpiochip_get_data(gc); 86 int ret; 87 88 switch (offset) { 89 case 0: 90 case 1: 91 case 2: 92 /* 93 * MUX can program the pin to be in EN1/2/3 pin mode 94 * Or GPIO1/2/3 mode. 95 * Setup the GPIO*_SEL MUX to GPIO mode 96 */ 97 ret = regmap_update_bits(gpio->map, 98 LP87565_REG_PIN_FUNCTION, 99 BIT(offset), BIT(offset)); 100 if (ret) 101 return ret; 102 103 break; 104 default: 105 return -EINVAL; 106 } 107 108 return 0; 109 } 110 111 static int lp87565_gpio_set_config(struct gpio_chip *gc, unsigned int offset, 112 unsigned long config) 113 { 114 struct lp87565_gpio *gpio = gpiochip_get_data(gc); 115 116 switch (pinconf_to_config_param(config)) { 117 case PIN_CONFIG_DRIVE_OPEN_DRAIN: 118 return regmap_update_bits(gpio->map, 119 LP87565_REG_GPIO_CONFIG, 120 BIT(offset + 121 __ffs(LP87565_GOIO1_OD)), 122 BIT(offset + 123 __ffs(LP87565_GOIO1_OD))); 124 case PIN_CONFIG_DRIVE_PUSH_PULL: 125 return regmap_update_bits(gpio->map, 126 LP87565_REG_GPIO_CONFIG, 127 BIT(offset + 128 __ffs(LP87565_GOIO1_OD)), 0); 129 default: 130 return -ENOTSUPP; 131 } 132 } 133 134 static const struct gpio_chip template_chip = { 135 .label = "lp87565-gpio", 136 .owner = THIS_MODULE, 137 .request = lp87565_gpio_request, 138 .get_direction = lp87565_gpio_get_direction, 139 .direction_input = lp87565_gpio_direction_input, 140 .direction_output = lp87565_gpio_direction_output, 141 .get = lp87565_gpio_get, 142 .set = lp87565_gpio_set, 143 .set_config = lp87565_gpio_set_config, 144 .base = -1, 145 .ngpio = 3, 146 .can_sleep = true, 147 }; 148 149 static int lp87565_gpio_probe(struct platform_device *pdev) 150 { 151 struct lp87565_gpio *gpio; 152 struct lp87565 *lp87565; 153 int ret; 154 155 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 156 if (!gpio) 157 return -ENOMEM; 158 159 lp87565 = dev_get_drvdata(pdev->dev.parent); 160 gpio->chip = template_chip; 161 gpio->chip.parent = lp87565->dev; 162 gpio->map = lp87565->regmap; 163 164 ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); 165 if (ret < 0) { 166 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 167 return ret; 168 } 169 170 return 0; 171 } 172 173 static const struct platform_device_id lp87565_gpio_id_table[] = { 174 { "lp87565-q1-gpio", }, 175 { /* sentinel */ } 176 }; 177 MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table); 178 179 static struct platform_driver lp87565_gpio_driver = { 180 .driver = { 181 .name = "lp87565-gpio", 182 }, 183 .probe = lp87565_gpio_probe, 184 .id_table = lp87565_gpio_id_table, 185 }; 186 module_platform_driver(lp87565_gpio_driver); 187 188 MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>"); 189 MODULE_DESCRIPTION("LP87565 GPIO driver"); 190 MODULE_LICENSE("GPL v2"); 191