xref: /linux/drivers/pinctrl/pinctrl-amdisp.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1e97435abSPratap Nirujogi /* SPDX-License-Identifier: GPL-2.0+ */
2e97435abSPratap Nirujogi /*
3e97435abSPratap Nirujogi  * AMD ISP Pinctrl Driver
4e97435abSPratap Nirujogi  *
5e97435abSPratap Nirujogi  * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
6e97435abSPratap Nirujogi  *
7e97435abSPratap Nirujogi  */
8e97435abSPratap Nirujogi 
9e97435abSPratap Nirujogi #include <linux/gpio/driver.h>
10e97435abSPratap Nirujogi #include <linux/module.h>
11e97435abSPratap Nirujogi #include <linux/platform_device.h>
12e97435abSPratap Nirujogi 
13e97435abSPratap Nirujogi #include "pinctrl-amdisp.h"
14e97435abSPratap Nirujogi 
15e97435abSPratap Nirujogi #define DRV_NAME		"amdisp-pinctrl"
16e97435abSPratap Nirujogi #define GPIO_CONTROL_PIN	4
17e97435abSPratap Nirujogi #define GPIO_OFFSET_0		0x0
18e97435abSPratap Nirujogi #define GPIO_OFFSET_1		0x4
19e97435abSPratap Nirujogi #define GPIO_OFFSET_2		0x50
20e97435abSPratap Nirujogi 
21e97435abSPratap Nirujogi static const u32 gpio_offset[] = {
22e97435abSPratap Nirujogi 	GPIO_OFFSET_0,
23e97435abSPratap Nirujogi 	GPIO_OFFSET_1,
24e97435abSPratap Nirujogi 	GPIO_OFFSET_2
25e97435abSPratap Nirujogi };
26e97435abSPratap Nirujogi 
27e97435abSPratap Nirujogi struct amdisp_pinctrl_data {
28e97435abSPratap Nirujogi 	const struct pinctrl_pin_desc *pins;
29e97435abSPratap Nirujogi 	unsigned int npins;
30e97435abSPratap Nirujogi 	const struct amdisp_function *functions;
31e97435abSPratap Nirujogi 	unsigned int nfunctions;
32e97435abSPratap Nirujogi 	const struct amdisp_pingroup *groups;
33e97435abSPratap Nirujogi 	unsigned int ngroups;
34e97435abSPratap Nirujogi };
35e97435abSPratap Nirujogi 
36e97435abSPratap Nirujogi static const struct amdisp_pinctrl_data amdisp_pinctrl_data = {
37e97435abSPratap Nirujogi 	.pins = amdisp_pins,
38e97435abSPratap Nirujogi 	.npins = ARRAY_SIZE(amdisp_pins),
39e97435abSPratap Nirujogi 	.functions = amdisp_functions,
40e97435abSPratap Nirujogi 	.nfunctions = ARRAY_SIZE(amdisp_functions),
41e97435abSPratap Nirujogi 	.groups = amdisp_groups,
42e97435abSPratap Nirujogi 	.ngroups = ARRAY_SIZE(amdisp_groups),
43e97435abSPratap Nirujogi };
44e97435abSPratap Nirujogi 
45e97435abSPratap Nirujogi struct amdisp_pinctrl {
46e97435abSPratap Nirujogi 	struct device *dev;
47e97435abSPratap Nirujogi 	struct pinctrl_dev *pctrl;
48e97435abSPratap Nirujogi 	struct pinctrl_desc desc;
49e97435abSPratap Nirujogi 	struct pinctrl_gpio_range gpio_range;
50e97435abSPratap Nirujogi 	struct gpio_chip gc;
51e97435abSPratap Nirujogi 	const struct amdisp_pinctrl_data *data;
52e97435abSPratap Nirujogi 	void __iomem *gpiobase;
53e97435abSPratap Nirujogi 	raw_spinlock_t lock;
54e97435abSPratap Nirujogi };
55e97435abSPratap Nirujogi 
56e97435abSPratap Nirujogi static int amdisp_get_groups_count(struct pinctrl_dev *pctldev)
57e97435abSPratap Nirujogi {
58e97435abSPratap Nirujogi 	struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
59e97435abSPratap Nirujogi 
60e97435abSPratap Nirujogi 	return pctrl->data->ngroups;
61e97435abSPratap Nirujogi }
62e97435abSPratap Nirujogi 
63e97435abSPratap Nirujogi static const char *amdisp_get_group_name(struct pinctrl_dev *pctldev,
64e97435abSPratap Nirujogi 					 unsigned int group)
65e97435abSPratap Nirujogi {
66e97435abSPratap Nirujogi 	struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
67e97435abSPratap Nirujogi 
68e97435abSPratap Nirujogi 	return pctrl->data->groups[group].name;
69e97435abSPratap Nirujogi }
70e97435abSPratap Nirujogi 
71e97435abSPratap Nirujogi static int amdisp_get_group_pins(struct pinctrl_dev *pctldev,
72e97435abSPratap Nirujogi 				 unsigned int group,
73e97435abSPratap Nirujogi 				 const unsigned int **pins,
74e97435abSPratap Nirujogi 				 unsigned int *num_pins)
75e97435abSPratap Nirujogi {
76e97435abSPratap Nirujogi 	struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
77e97435abSPratap Nirujogi 
78e97435abSPratap Nirujogi 	*pins = pctrl->data->groups[group].pins;
79e97435abSPratap Nirujogi 	*num_pins = pctrl->data->groups[group].npins;
80e97435abSPratap Nirujogi 	return 0;
81e97435abSPratap Nirujogi }
82e97435abSPratap Nirujogi 
83e97435abSPratap Nirujogi const struct pinctrl_ops amdisp_pinctrl_ops = {
84e97435abSPratap Nirujogi 	.get_groups_count	= amdisp_get_groups_count,
85e97435abSPratap Nirujogi 	.get_group_name		= amdisp_get_group_name,
86e97435abSPratap Nirujogi 	.get_group_pins		= amdisp_get_group_pins,
87e97435abSPratap Nirujogi };
88e97435abSPratap Nirujogi 
89e97435abSPratap Nirujogi static int amdisp_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
90e97435abSPratap Nirujogi {
91e97435abSPratap Nirujogi 	/* amdisp gpio only has output mode */
92e97435abSPratap Nirujogi 	return GPIO_LINE_DIRECTION_OUT;
93e97435abSPratap Nirujogi }
94e97435abSPratap Nirujogi 
95e97435abSPratap Nirujogi static int amdisp_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
96e97435abSPratap Nirujogi {
97e97435abSPratap Nirujogi 	return -EOPNOTSUPP;
98e97435abSPratap Nirujogi }
99e97435abSPratap Nirujogi 
100e97435abSPratap Nirujogi static int amdisp_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
101e97435abSPratap Nirujogi 					int value)
102e97435abSPratap Nirujogi {
103e97435abSPratap Nirujogi 	/* Nothing to do, amdisp gpio only has output mode */
104e97435abSPratap Nirujogi 	return 0;
105e97435abSPratap Nirujogi }
106e97435abSPratap Nirujogi 
107e97435abSPratap Nirujogi static int amdisp_gpio_get(struct gpio_chip *gc, unsigned int gpio)
108e97435abSPratap Nirujogi {
109e97435abSPratap Nirujogi 	unsigned long flags;
110e97435abSPratap Nirujogi 	u32 pin_reg;
111e97435abSPratap Nirujogi 	struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc);
112e97435abSPratap Nirujogi 
113e97435abSPratap Nirujogi 	raw_spin_lock_irqsave(&pctrl->lock, flags);
114e97435abSPratap Nirujogi 	pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]);
115e97435abSPratap Nirujogi 	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
116e97435abSPratap Nirujogi 
117e97435abSPratap Nirujogi 	return !!(pin_reg & BIT(GPIO_CONTROL_PIN));
118e97435abSPratap Nirujogi }
119e97435abSPratap Nirujogi 
120e97435abSPratap Nirujogi static void amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
121e97435abSPratap Nirujogi {
122e97435abSPratap Nirujogi 	unsigned long flags;
123e97435abSPratap Nirujogi 	u32 pin_reg;
124e97435abSPratap Nirujogi 	struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc);
125e97435abSPratap Nirujogi 
126e97435abSPratap Nirujogi 	raw_spin_lock_irqsave(&pctrl->lock, flags);
127e97435abSPratap Nirujogi 	pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]);
128e97435abSPratap Nirujogi 	if (value)
129e97435abSPratap Nirujogi 		pin_reg |= BIT(GPIO_CONTROL_PIN);
130e97435abSPratap Nirujogi 	else
131e97435abSPratap Nirujogi 		pin_reg &= ~BIT(GPIO_CONTROL_PIN);
132e97435abSPratap Nirujogi 	writel(pin_reg, pctrl->gpiobase + gpio_offset[gpio]);
133e97435abSPratap Nirujogi 	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
134e97435abSPratap Nirujogi }
135e97435abSPratap Nirujogi 
136e97435abSPratap Nirujogi static int amdisp_gpiochip_add(struct platform_device *pdev,
137e97435abSPratap Nirujogi 			       struct amdisp_pinctrl *pctrl)
138e97435abSPratap Nirujogi {
139e97435abSPratap Nirujogi 	struct gpio_chip *gc = &pctrl->gc;
140e97435abSPratap Nirujogi 	struct pinctrl_gpio_range *grange = &pctrl->gpio_range;
141e97435abSPratap Nirujogi 	int ret;
142e97435abSPratap Nirujogi 
143e97435abSPratap Nirujogi 	gc->label		= dev_name(pctrl->dev);
144e97435abSPratap Nirujogi 	gc->parent		= &pdev->dev;
145e97435abSPratap Nirujogi 	gc->names		= amdisp_range_pins_name;
146e97435abSPratap Nirujogi 	gc->request		= gpiochip_generic_request;
147e97435abSPratap Nirujogi 	gc->free		= gpiochip_generic_free;
148e97435abSPratap Nirujogi 	gc->get_direction	= amdisp_gpio_get_direction;
149e97435abSPratap Nirujogi 	gc->direction_input	= amdisp_gpio_direction_input;
150e97435abSPratap Nirujogi 	gc->direction_output	= amdisp_gpio_direction_output;
151e97435abSPratap Nirujogi 	gc->get			= amdisp_gpio_get;
152e97435abSPratap Nirujogi 	gc->set			= amdisp_gpio_set;
153e97435abSPratap Nirujogi 	gc->base		= -1;
154e97435abSPratap Nirujogi 	gc->ngpio		= ARRAY_SIZE(amdisp_range_pins);
155e97435abSPratap Nirujogi 
156e97435abSPratap Nirujogi 	grange->id		= 0;
157e97435abSPratap Nirujogi 	grange->pin_base	= 0;
158e97435abSPratap Nirujogi 	grange->base		= 0;
159e97435abSPratap Nirujogi 	grange->pins		= amdisp_range_pins;
160e97435abSPratap Nirujogi 	grange->npins		= ARRAY_SIZE(amdisp_range_pins);
161e97435abSPratap Nirujogi 	grange->name		= gc->label;
162e97435abSPratap Nirujogi 	grange->gc		= gc;
163e97435abSPratap Nirujogi 
164e97435abSPratap Nirujogi 	ret = devm_gpiochip_add_data(&pdev->dev, gc, pctrl);
165e97435abSPratap Nirujogi 	if (ret)
166e97435abSPratap Nirujogi 		return ret;
167e97435abSPratap Nirujogi 
168e97435abSPratap Nirujogi 	pinctrl_add_gpio_range(pctrl->pctrl, grange);
169e97435abSPratap Nirujogi 
170e97435abSPratap Nirujogi 	return 0;
171e97435abSPratap Nirujogi }
172e97435abSPratap Nirujogi 
173e97435abSPratap Nirujogi static int amdisp_pinctrl_probe(struct platform_device *pdev)
174e97435abSPratap Nirujogi {
175e97435abSPratap Nirujogi 	struct amdisp_pinctrl *pctrl;
176e97435abSPratap Nirujogi 	struct resource *res;
177e97435abSPratap Nirujogi 	int ret;
178e97435abSPratap Nirujogi 
179e97435abSPratap Nirujogi 	pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
180e97435abSPratap Nirujogi 	if (!pctrl)
181e97435abSPratap Nirujogi 		return -ENOMEM;
182e97435abSPratap Nirujogi 
183e97435abSPratap Nirujogi 	pdev->dev.init_name = DRV_NAME;
184e97435abSPratap Nirujogi 
185e97435abSPratap Nirujogi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
186*465cf676SDan Carpenter 	if (!res)
187*465cf676SDan Carpenter 		return -EINVAL;
188e97435abSPratap Nirujogi 
189e97435abSPratap Nirujogi 	pctrl->gpiobase = devm_ioremap_resource(&pdev->dev, res);
190e97435abSPratap Nirujogi 	if (IS_ERR(pctrl->gpiobase))
191e97435abSPratap Nirujogi 		return PTR_ERR(pctrl->gpiobase);
192e97435abSPratap Nirujogi 
193e97435abSPratap Nirujogi 	platform_set_drvdata(pdev, pctrl);
194e97435abSPratap Nirujogi 
195e97435abSPratap Nirujogi 	pctrl->dev = &pdev->dev;
196e97435abSPratap Nirujogi 	pctrl->data = &amdisp_pinctrl_data;
197e97435abSPratap Nirujogi 	pctrl->desc.owner = THIS_MODULE;
198e97435abSPratap Nirujogi 	pctrl->desc.pctlops = &amdisp_pinctrl_ops;
199e97435abSPratap Nirujogi 	pctrl->desc.pmxops = NULL;
200e97435abSPratap Nirujogi 	pctrl->desc.name = dev_name(&pdev->dev);
201e97435abSPratap Nirujogi 	pctrl->desc.pins = pctrl->data->pins;
202e97435abSPratap Nirujogi 	pctrl->desc.npins = pctrl->data->npins;
203e97435abSPratap Nirujogi 	ret = devm_pinctrl_register_and_init(&pdev->dev, &pctrl->desc,
204e97435abSPratap Nirujogi 					     pctrl, &pctrl->pctrl);
205e97435abSPratap Nirujogi 	if (ret)
206e97435abSPratap Nirujogi 		return ret;
207e97435abSPratap Nirujogi 
208e97435abSPratap Nirujogi 	ret = pinctrl_enable(pctrl->pctrl);
209e97435abSPratap Nirujogi 	if (ret)
210e97435abSPratap Nirujogi 		return ret;
211e97435abSPratap Nirujogi 
212e97435abSPratap Nirujogi 	ret = amdisp_gpiochip_add(pdev, pctrl);
213e97435abSPratap Nirujogi 	if (ret)
214e97435abSPratap Nirujogi 		return ret;
215e97435abSPratap Nirujogi 
216e97435abSPratap Nirujogi 	return 0;
217e97435abSPratap Nirujogi }
218e97435abSPratap Nirujogi 
219e97435abSPratap Nirujogi static struct platform_driver amdisp_pinctrl_driver = {
220e97435abSPratap Nirujogi 	.driver = {
221e97435abSPratap Nirujogi 		.name = DRV_NAME,
222e97435abSPratap Nirujogi 	},
223e97435abSPratap Nirujogi 	.probe = amdisp_pinctrl_probe,
224e97435abSPratap Nirujogi };
225e97435abSPratap Nirujogi module_platform_driver(amdisp_pinctrl_driver);
226e97435abSPratap Nirujogi 
227e97435abSPratap Nirujogi MODULE_AUTHOR("Benjamin Chan <benjamin.chan@amd.com>");
228e97435abSPratap Nirujogi MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
229e97435abSPratap Nirujogi MODULE_DESCRIPTION("AMDISP pinctrl driver");
230e97435abSPratap Nirujogi MODULE_LICENSE("GPL v2");
231e97435abSPratap Nirujogi MODULE_ALIAS("platform:" DRV_NAME);
232