230 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2015 Verifone Int.4 *5 * Author: Nicolas Saenz Julienne <nicolassaenzj@gmail.com>6 *7 * This driver is based on the gpio-tps65912 implementation.8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/errno.h>13#include <linux/gpio/driver.h>14#include <linux/platform_device.h>15#include <linux/regmap.h>16#include <linux/mfd/tps65218.h>17 18struct tps65218_gpio {19 struct tps65218 *tps65218;20 struct gpio_chip gpio_chip;21};22 23static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset)24{25 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);26 struct tps65218 *tps65218 = tps65218_gpio->tps65218;27 unsigned int val;28 int ret;29 30 ret = regmap_read(tps65218->regmap, TPS65218_REG_ENABLE2, &val);31 if (ret)32 return ret;33 34 return !!(val & (TPS65218_ENABLE2_GPIO1 << offset));35}36 37static void tps65218_gpio_set(struct gpio_chip *gc, unsigned offset,38 int value)39{40 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);41 struct tps65218 *tps65218 = tps65218_gpio->tps65218;42 43 if (value)44 tps65218_set_bits(tps65218, TPS65218_REG_ENABLE2,45 TPS65218_ENABLE2_GPIO1 << offset,46 TPS65218_ENABLE2_GPIO1 << offset,47 TPS65218_PROTECT_L1);48 else49 tps65218_clear_bits(tps65218, TPS65218_REG_ENABLE2,50 TPS65218_ENABLE2_GPIO1 << offset,51 TPS65218_PROTECT_L1);52}53 54static int tps65218_gpio_output(struct gpio_chip *gc, unsigned offset,55 int value)56{57 /* Only drives GPOs */58 tps65218_gpio_set(gc, offset, value);59 return 0;60}61 62static int tps65218_gpio_input(struct gpio_chip *gc, unsigned offset)63{64 return -EPERM;65}66 67static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)68{69 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);70 struct tps65218 *tps65218 = tps65218_gpio->tps65218;71 int ret;72 73 if (gpiochip_line_is_open_source(gc, offset)) {74 dev_err(gc->parent, "can't work as open source\n");75 return -EINVAL;76 }77 78 switch (offset) {79 case 0:80 if (!gpiochip_line_is_open_drain(gc, offset)) {81 dev_err(gc->parent, "GPO1 works only as open drain\n");82 return -EINVAL;83 }84 85 /* Disable sequencer for GPO1 */86 ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7,87 TPS65218_SEQ7_GPO1_SEQ_MASK,88 TPS65218_PROTECT_L1);89 if (ret)90 return ret;91 92 /* Setup GPO1 */93 ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,94 TPS65218_CONFIG1_IO1_SEL,95 TPS65218_PROTECT_L1);96 if (ret)97 return ret;98 99 break;100 case 1:101 /* Setup GPO2 */102 ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,103 TPS65218_CONFIG1_IO1_SEL,104 TPS65218_PROTECT_L1);105 if (ret)106 return ret;107 108 break;109 110 case 2:111 if (!gpiochip_line_is_open_drain(gc, offset)) {112 dev_err(gc->parent, "GPO3 works only as open drain\n");113 return -EINVAL;114 }115 116 /* Disable sequencer for GPO3 */117 ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7,118 TPS65218_SEQ7_GPO3_SEQ_MASK,119 TPS65218_PROTECT_L1);120 if (ret)121 return ret;122 123 /* Setup GPO3 */124 ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG2,125 TPS65218_CONFIG2_DC12_RST,126 TPS65218_PROTECT_L1);127 if (ret)128 return ret;129 130 break;131 default:132 return -EINVAL;133 }134 135 return 0;136}137 138static int tps65218_gpio_set_config(struct gpio_chip *gc, unsigned offset,139 unsigned long config)140{141 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);142 struct tps65218 *tps65218 = tps65218_gpio->tps65218;143 enum pin_config_param param = pinconf_to_config_param(config);144 145 switch (offset) {146 case 0:147 case 2:148 /* GPO1 is hardwired to be open drain */149 if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)150 return 0;151 return -ENOTSUPP;152 case 1:153 /* GPO2 is push-pull by default, can be set as open drain. */154 if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)155 return tps65218_clear_bits(tps65218,156 TPS65218_REG_CONFIG1,157 TPS65218_CONFIG1_GPO2_BUF,158 TPS65218_PROTECT_L1);159 if (param == PIN_CONFIG_DRIVE_PUSH_PULL)160 return tps65218_set_bits(tps65218,161 TPS65218_REG_CONFIG1,162 TPS65218_CONFIG1_GPO2_BUF,163 TPS65218_CONFIG1_GPO2_BUF,164 TPS65218_PROTECT_L1);165 return -ENOTSUPP;166 default:167 break;168 }169 return -ENOTSUPP;170}171 172static const struct gpio_chip template_chip = {173 .label = "gpio-tps65218",174 .owner = THIS_MODULE,175 .request = tps65218_gpio_request,176 .direction_output = tps65218_gpio_output,177 .direction_input = tps65218_gpio_input,178 .get = tps65218_gpio_get,179 .set = tps65218_gpio_set,180 .set_config = tps65218_gpio_set_config,181 .can_sleep = true,182 .ngpio = 3,183 .base = -1,184};185 186static int tps65218_gpio_probe(struct platform_device *pdev)187{188 struct tps65218 *tps65218 = dev_get_drvdata(pdev->dev.parent);189 struct tps65218_gpio *tps65218_gpio;190 191 tps65218_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65218_gpio),192 GFP_KERNEL);193 if (!tps65218_gpio)194 return -ENOMEM;195 196 tps65218_gpio->tps65218 = tps65218;197 tps65218_gpio->gpio_chip = template_chip;198 tps65218_gpio->gpio_chip.parent = &pdev->dev;199 200 return devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip,201 tps65218_gpio);202}203 204static const struct of_device_id tps65218_dt_match[] = {205 { .compatible = "ti,tps65218-gpio" },206 { }207};208MODULE_DEVICE_TABLE(of, tps65218_dt_match);209 210static const struct platform_device_id tps65218_gpio_id_table[] = {211 { "tps65218-gpio", },212 { /* sentinel */ }213};214MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);215 216static struct platform_driver tps65218_gpio_driver = {217 .driver = {218 .name = "tps65218-gpio",219 .of_match_table = tps65218_dt_match,220 },221 .probe = tps65218_gpio_probe,222 .id_table = tps65218_gpio_id_table,223};224 225module_platform_driver(tps65218_gpio_driver);226 227MODULE_AUTHOR("Nicolas Saenz Julienne <nicolassaenzj@gmail.com>");228MODULE_DESCRIPTION("GPO interface for TPS65218 PMICs");229MODULE_LICENSE("GPL v2");230