1135446Strhodes// SPDX-License-Identifier: GPL-2.0-only
2193149Sdougb/*
3135446Strhodes * TI Palma series PMIC's GPIO driver.
4135446Strhodes *
5193149Sdougb * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
6135446Strhodes *
7135446Strhodes * Author: Laxman Dewangan <ldewangan@nvidia.com>
8135446Strhodes */
9135446Strhodes
10135446Strhodes#include <linux/gpio/driver.h>
11135446Strhodes#include <linux/kernel.h>
12135446Strhodes#include <linux/init.h>
13135446Strhodes#include <linux/mfd/palmas.h>
14135446Strhodes#include <linux/of.h>
15135446Strhodes#include <linux/platform_device.h>
16135446Strhodes
17135446Strhodesstruct palmas_gpio {
18193149Sdougb	struct gpio_chip gpio_chip;
19135446Strhodes	struct palmas *palmas;
20135446Strhodes};
21135446Strhodes
22135446Strhodesstruct palmas_device_data {
23170222Sdougb	int ngpio;
24135446Strhodes};
25135446Strhodes
26135446Strhodesstatic int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
27135446Strhodes{
28135446Strhodes	struct palmas_gpio *pg = gpiochip_get_data(gc);
29135446Strhodes	struct palmas *palmas = pg->palmas;
30193149Sdougb	unsigned int val;
31170222Sdougb	int ret;
32170222Sdougb	unsigned int reg;
33170222Sdougb	int gpio16 = (offset/8);
34135446Strhodes
35135446Strhodes	offset %= 8;
36135446Strhodes	reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
37135446Strhodes
38135446Strhodes	ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
39135446Strhodes	if (ret < 0) {
40135446Strhodes		dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
41135446Strhodes		return ret;
42135446Strhodes	}
43135446Strhodes
44135446Strhodes	if (val & BIT(offset))
45170222Sdougb		reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT;
46170222Sdougb	else
47135446Strhodes		reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN;
48135446Strhodes
49135446Strhodes	ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
50135446Strhodes	if (ret < 0) {
51135446Strhodes		dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
52135446Strhodes		return ret;
53135446Strhodes	}
54135446Strhodes	return !!(val & BIT(offset));
55135446Strhodes}
56135446Strhodes
57135446Strhodesstatic void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
58135446Strhodes			int value)
59135446Strhodes{
60135446Strhodes	struct palmas_gpio *pg = gpiochip_get_data(gc);
61135446Strhodes	struct palmas *palmas = pg->palmas;
62135446Strhodes	int ret;
63135446Strhodes	unsigned int reg;
64135446Strhodes	int gpio16 = (offset/8);
65135446Strhodes
66135446Strhodes	offset %= 8;
67135446Strhodes	if (gpio16)
68135446Strhodes		reg = (value) ?
69170222Sdougb			PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2;
70135446Strhodes	else
71135446Strhodes		reg = (value) ?
72170222Sdougb			PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT;
73170222Sdougb
74170222Sdougb	ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));
75170222Sdougb	if (ret < 0)
76170222Sdougb		dev_err(gc->parent, "Reg 0x%02x write failed, %d\n", reg, ret);
77135446Strhodes}
78135446Strhodes
79135446Strhodesstatic int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
80135446Strhodes				int value)
81135446Strhodes{
82135446Strhodes	struct palmas_gpio *pg = gpiochip_get_data(gc);
83135446Strhodes	struct palmas *palmas = pg->palmas;
84135446Strhodes	int ret;
85135446Strhodes	unsigned int reg;
86135446Strhodes	int gpio16 = (offset/8);
87135446Strhodes
88135446Strhodes	offset %= 8;
89135446Strhodes	reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
90135446Strhodes
91135446Strhodes	/* Set the initial value */
92135446Strhodes	palmas_gpio_set(gc, offset, value);
93135446Strhodes
94135446Strhodes	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,
95135446Strhodes				BIT(offset), BIT(offset));
96135446Strhodes	if (ret < 0)
97135446Strhodes		dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
98170222Sdougb			ret);
99135446Strhodes	return ret;
100170222Sdougb}
101170222Sdougb
102135446Strhodesstatic int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
103170222Sdougb{
104170222Sdougb	struct palmas_gpio *pg = gpiochip_get_data(gc);
105170222Sdougb	struct palmas *palmas = pg->palmas;
106170222Sdougb	int ret;
107170222Sdougb	unsigned int reg;
108170222Sdougb	int gpio16 = (offset/8);
109170222Sdougb
110170222Sdougb	offset %= 8;
111170222Sdougb	reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
112170222Sdougb
113170222Sdougb	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
114170222Sdougb	if (ret < 0)
115170222Sdougb		dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
116170222Sdougb			ret);
117170222Sdougb	return ret;
118170222Sdougb}
119170222Sdougb
120170222Sdougbstatic int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
121170222Sdougb{
122170222Sdougb	struct palmas_gpio *pg = gpiochip_get_data(gc);
123170222Sdougb	struct palmas *palmas = pg->palmas;
124170222Sdougb
125170222Sdougb	return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
126170222Sdougb}
127170222Sdougb
128170222Sdougbstatic const struct palmas_device_data palmas_dev_data = {
129170222Sdougb	.ngpio = 8,
130170222Sdougb};
131170222Sdougb
132170222Sdougbstatic const struct palmas_device_data tps80036_dev_data = {
133170222Sdougb	.ngpio = 16,
134170222Sdougb};
135170222Sdougb
136170222Sdougbstatic const struct of_device_id of_palmas_gpio_match[] = {
137170222Sdougb	{ .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,},
138170222Sdougb	{ .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,},
139170222Sdougb	{ .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,},
140170222Sdougb	{ .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,},
141135446Strhodes	{ },
142135446Strhodes};
143135446Strhodes
144135446Strhodesstatic int palmas_gpio_probe(struct platform_device *pdev)
145170222Sdougb{
146135446Strhodes	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
147135446Strhodes	struct palmas_platform_data *palmas_pdata;
148135446Strhodes	struct palmas_gpio *palmas_gpio;
149135446Strhodes	int ret;
150135446Strhodes	const struct palmas_device_data *dev_data;
151135446Strhodes
152135446Strhodes	dev_data = of_device_get_match_data(&pdev->dev);
153135446Strhodes	if (!dev_data)
154170222Sdougb		dev_data = &palmas_dev_data;
155170222Sdougb
156170222Sdougb	palmas_gpio = devm_kzalloc(&pdev->dev,
157170222Sdougb				sizeof(*palmas_gpio), GFP_KERNEL);
158170222Sdougb	if (!palmas_gpio)
159170222Sdougb		return -ENOMEM;
160170222Sdougb
161170222Sdougb	palmas_gpio->palmas = palmas;
162170222Sdougb	palmas_gpio->gpio_chip.owner = THIS_MODULE;
163170222Sdougb	palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
164170222Sdougb	palmas_gpio->gpio_chip.ngpio = dev_data->ngpio;
165135446Strhodes	palmas_gpio->gpio_chip.can_sleep = true;
166135446Strhodes	palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
167135446Strhodes	palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
168135446Strhodes	palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
169135446Strhodes	palmas_gpio->gpio_chip.set	= palmas_gpio_set;
170135446Strhodes	palmas_gpio->gpio_chip.get	= palmas_gpio_get;
171135446Strhodes	palmas_gpio->gpio_chip.parent = &pdev->dev;
172135446Strhodes
173135446Strhodes	palmas_pdata = dev_get_platdata(palmas->dev);
174135446Strhodes	if (palmas_pdata && palmas_pdata->gpio_base)
175135446Strhodes		palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
176170222Sdougb	else
177135446Strhodes		palmas_gpio->gpio_chip.base = -1;
178135446Strhodes
179135446Strhodes	ret = devm_gpiochip_add_data(&pdev->dev, &palmas_gpio->gpio_chip,
180135446Strhodes				     palmas_gpio);
181135446Strhodes	if (ret < 0) {
182135446Strhodes		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
183135446Strhodes		return ret;
184135446Strhodes	}
185135446Strhodes
186135446Strhodes	return ret;
187135446Strhodes}
188170222Sdougb
189170222Sdougbstatic struct platform_driver palmas_gpio_driver = {
190135446Strhodes	.driver.name	= "palmas-gpio",
191135446Strhodes	.driver.of_match_table = of_palmas_gpio_match,
192135446Strhodes	.probe		= palmas_gpio_probe,
193135446Strhodes};
194135446Strhodes
195135446Strhodesstatic int __init palmas_gpio_init(void)
196135446Strhodes{
197135446Strhodes	return platform_driver_register(&palmas_gpio_driver);
198170222Sdougb}
199135446Strhodessubsys_initcall(palmas_gpio_init);
200135446Strhodes