brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · cd1f170 Raw
186 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * GPIO driver for TI TPS65219 PMICs4 *5 * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/6 */7 8#include <linux/bits.h>9#include <linux/gpio/driver.h>10#include <linux/mfd/tps65219.h>11#include <linux/module.h>12#include <linux/platform_device.h>13#include <linux/regmap.h>14 15#define TPS65219_GPIO0_DIR_MASK		BIT(3)16#define TPS65219_GPIO0_OFFSET		217#define TPS65219_GPIO0_IDX		018#define TPS65219_GPIO_DIR_IN		119#define TPS65219_GPIO_DIR_OUT		020 21struct tps65219_gpio {22	struct gpio_chip gpio_chip;23	struct tps65219 *tps;24};25 26static int tps65219_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)27{28	struct tps65219_gpio *gpio = gpiochip_get_data(gc);29	int ret, val;30 31	if (offset != TPS65219_GPIO0_IDX)32		return GPIO_LINE_DIRECTION_OUT;33 34	ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG, &val);35	if (ret)36		return ret;37 38	return !!(val & TPS65219_GPIO0_DIR_MASK);39}40 41static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)42{43	struct tps65219_gpio *gpio = gpiochip_get_data(gc);44	struct device *dev = gpio->tps->dev;45	int ret, val;46 47	if (offset != TPS65219_GPIO0_IDX) {48		dev_err(dev, "GPIO%d is output only, cannot get\n", offset);49		return -ENOTSUPP;50	}51 52	ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_CTRL, &val);53	if (ret)54		return ret;55 56	ret = !!(val & BIT(TPS65219_MFP_GPIO_STATUS_MASK));57	dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret);58 59	/*60	 * Depending on NVM config, return an error if direction is output, otherwise the GPIO061	 * status bit.62	 */63 64	if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)65		return -ENOTSUPP;66 67	return ret;68}69 70static void tps65219_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)71{72	struct tps65219_gpio *gpio = gpiochip_get_data(gc);73	struct device *dev = gpio->tps->dev;74	int v, mask, bit;75 76	bit = (offset == TPS65219_GPIO0_IDX) ? TPS65219_GPIO0_OFFSET : offset - 1;77 78	mask = BIT(bit);79	v = value ? mask : 0;80 81	if (regmap_update_bits(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG, mask, v))82		dev_err(dev, "GPIO%d, set to value %d failed.\n", offset, value);83}84 85static int tps65219_gpio_change_direction(struct gpio_chip *gc, unsigned int offset,86					  unsigned int direction)87{88	struct tps65219_gpio *gpio = gpiochip_get_data(gc);89	struct device *dev = gpio->tps->dev;90 91	/*92	 * Documentation is stating that GPIO0 direction must not be changed in Linux:93	 * Table 8-34. MFP_1_CONFIG(3): MULTI_DEVICE_ENABLE, should only be changed in INITIALIZE94	 * state (prior to ON Request).95	 * Set statically by NVM, changing direction in application can cause a hang.96	 * Below can be used for test purpose only.97	 */98 99#if 0100	int ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG,101				     TPS65219_GPIO0_DIR_MASK, direction);102	if (ret) {103		dev_err(dev,104			"GPIO DEBUG enabled: Fail to change direction to %u for GPIO%d.\n",105			direction, offset);106		return ret;107	}108#endif109 110	dev_err(dev,111		"GPIO%d direction set by NVM, change to %u failed, not allowed by specification\n",112		 offset, direction);113 114	return -ENOTSUPP;115}116 117static int tps65219_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)118{119	struct tps65219_gpio *gpio = gpiochip_get_data(gc);120	struct device *dev = gpio->tps->dev;121 122	if (offset != TPS65219_GPIO0_IDX) {123		dev_err(dev, "GPIO%d is output only, cannot change to input\n", offset);124		return -ENOTSUPP;125	}126 127	if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_IN)128		return 0;129 130	return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_IN);131}132 133static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)134{135	tps65219_gpio_set(gc, offset, value);136	if (offset != TPS65219_GPIO0_IDX)137		return 0;138 139	if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)140		return 0;141 142	return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_OUT);143}144 145static const struct gpio_chip tps65219_template_chip = {146	.label			= "tps65219-gpio",147	.owner			= THIS_MODULE,148	.get_direction		= tps65219_gpio_get_direction,149	.direction_input	= tps65219_gpio_direction_input,150	.direction_output	= tps65219_gpio_direction_output,151	.get			= tps65219_gpio_get,152	.set			= tps65219_gpio_set,153	.base			= -1,154	.ngpio			= 3,155	.can_sleep		= true,156};157 158static int tps65219_gpio_probe(struct platform_device *pdev)159{160	struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);161	struct tps65219_gpio *gpio;162 163	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);164	if (!gpio)165		return -ENOMEM;166 167	gpio->tps = tps;168	gpio->gpio_chip = tps65219_template_chip;169	gpio->gpio_chip.parent = tps->dev;170 171	return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip, gpio);172}173 174static struct platform_driver tps65219_gpio_driver = {175	.driver = {176		.name = "tps65219-gpio",177	},178	.probe = tps65219_gpio_probe,179};180module_platform_driver(tps65219_gpio_driver);181 182MODULE_ALIAS("platform:tps65219-gpio");183MODULE_AUTHOR("Jonathan Cormier <jcormier@criticallink.com>");184MODULE_DESCRIPTION("TPS65219 GPIO driver");185MODULE_LICENSE("GPL");186