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(struct gpio_chip *chip, unsigned int offset) 30 { 31 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 32 int ret, val; 33 34 ret = regmap_read(gpio->map, LP87565_REG_GPIO_IN, &val); 35 if (ret < 0) 36 return ret; 37 38 return !!(val & BIT(offset)); 39 } 40 41 static void lp87565_gpio_set(struct gpio_chip *chip, unsigned int offset, 42 int value) 43 { 44 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 45 46 regmap_update_bits(gpio->map, LP87565_REG_GPIO_OUT, 47 BIT(offset), value ? BIT(offset) : 0); 48 } 49 50 static int lp87565_gpio_get_direction(struct gpio_chip *chip, 51 unsigned int offset) 52 { 53 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 54 int ret, val; 55 56 ret = regmap_read(gpio->map, LP87565_REG_GPIO_CONFIG, &val); 57 if (ret < 0) 58 return ret; 59 60 if (val & BIT(offset)) 61 return GPIO_LINE_DIRECTION_OUT; 62 63 return GPIO_LINE_DIRECTION_IN; 64 } 65 66 static int lp87565_gpio_direction_input(struct gpio_chip *chip, 67 unsigned int offset) 68 { 69 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 70 71 return regmap_update_bits(gpio->map, 72 LP87565_REG_GPIO_CONFIG, 73 BIT(offset), 0); 74 } 75 76 static int lp87565_gpio_direction_output(struct gpio_chip *chip, 77 unsigned int offset, int value) 78 { 79 struct lp87565_gpio *gpio = gpiochip_get_data(chip); 80 81 lp87565_gpio_set(chip, offset, value); 82 83 return regmap_update_bits(gpio->map, 84 LP87565_REG_GPIO_CONFIG, 85 BIT(offset), BIT(offset)); 86 } 87 88 static int lp87565_gpio_request(struct gpio_chip *gc, unsigned int offset) 89 { 90 struct lp87565_gpio *gpio = gpiochip_get_data(gc); 91 int ret; 92 93 switch (offset) { 94 case 0: 95 case 1: 96 case 2: 97 /* 98 * MUX can program the pin to be in EN1/2/3 pin mode 99 * Or GPIO1/2/3 mode. 100 * Setup the GPIO*_SEL MUX to GPIO mode 101 */ 102 ret = regmap_update_bits(gpio->map, 103 LP87565_REG_PIN_FUNCTION, 104 BIT(offset), BIT(offset)); 105 if (ret) 106 return ret; 107 108 break; 109 default: 110 return -EINVAL; 111 } 112 113 return 0; 114 } 115 116 static int lp87565_gpio_set_config(struct gpio_chip *gc, unsigned int offset, 117 unsigned long config) 118 { 119 struct lp87565_gpio *gpio = gpiochip_get_data(gc); 120 121 switch (pinconf_to_config_param(config)) { 122 case PIN_CONFIG_DRIVE_OPEN_DRAIN: 123 return regmap_update_bits(gpio->map, 124 LP87565_REG_GPIO_CONFIG, 125 BIT(offset + 126 __ffs(LP87565_GOIO1_OD)), 127 BIT(offset + 128 __ffs(LP87565_GOIO1_OD))); 129 case PIN_CONFIG_DRIVE_PUSH_PULL: 130 return regmap_update_bits(gpio->map, 131 LP87565_REG_GPIO_CONFIG, 132 BIT(offset + 133 __ffs(LP87565_GOIO1_OD)), 0); 134 default: 135 return -ENOTSUPP; 136 } 137 } 138 139 static const struct gpio_chip template_chip = { 140 .label = "lp87565-gpio", 141 .owner = THIS_MODULE, 142 .request = lp87565_gpio_request, 143 .get_direction = lp87565_gpio_get_direction, 144 .direction_input = lp87565_gpio_direction_input, 145 .direction_output = lp87565_gpio_direction_output, 146 .get = lp87565_gpio_get, 147 .set = lp87565_gpio_set, 148 .set_config = lp87565_gpio_set_config, 149 .base = -1, 150 .ngpio = 3, 151 .can_sleep = true, 152 }; 153 154 static int lp87565_gpio_probe(struct platform_device *pdev) 155 { 156 struct lp87565_gpio *gpio; 157 struct lp87565 *lp87565; 158 int ret; 159 160 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 161 if (!gpio) 162 return -ENOMEM; 163 164 lp87565 = dev_get_drvdata(pdev->dev.parent); 165 gpio->chip = template_chip; 166 gpio->chip.parent = lp87565->dev; 167 gpio->map = lp87565->regmap; 168 169 ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); 170 if (ret < 0) { 171 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 172 return ret; 173 } 174 175 return 0; 176 } 177 178 static const struct platform_device_id lp87565_gpio_id_table[] = { 179 { "lp87565-q1-gpio", }, 180 { /* sentinel */ } 181 }; 182 MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table); 183 184 static struct platform_driver lp87565_gpio_driver = { 185 .driver = { 186 .name = "lp87565-gpio", 187 }, 188 .probe = lp87565_gpio_probe, 189 .id_table = lp87565_gpio_id_table, 190 }; 191 module_platform_driver(lp87565_gpio_driver); 192 193 MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>"); 194 MODULE_DESCRIPTION("LP87565 GPIO driver"); 195 MODULE_LICENSE("GPL v2"); 196