1// SPDX-License-Identifier: GPL-2.0
2/*
3 * RZ/G2L Pin Function Controller
4 *
5 * Copyright (C) 2021-2023 Renesas Electronics Corp.
6 */
7
8#include <asm-generic/gpio.h>
9#include <asm/io.h>
10#include <dm/device.h>
11#include <dm/device_compat.h>
12#include <renesas/rzg2l-pfc.h>
13
14static void rzg2l_gpio_set(const struct rzg2l_pfc_data *data, u32 port, u8 pin,
15			   bool value)
16{
17	if (value)
18		setbits_8(data->base + P(port), BIT(pin));
19	else
20		clrbits_8(data->base + P(port), BIT(pin));
21}
22
23static int rzg2l_gpio_get_value(struct udevice *dev, unsigned int offset)
24{
25	const struct rzg2l_pfc_data *data =
26		(const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
27	const u32 port = RZG2L_PINMUX_TO_PORT(offset);
28	const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
29	u16 pm_state;
30
31	pm_state = (readw(data->base + PM(port)) >> (pin * 2)) & PM_MASK;
32	switch (pm_state) {
33	case PM_INPUT:
34		return !!(readb(data->base + PIN(port)) & BIT(pin));
35	case PM_OUTPUT:
36	case PM_OUTPUT_IEN:
37		return !!(readb(data->base + P(port)) & BIT(pin));
38	default:	/* PM_HIGH_Z */
39		return 0;
40	}
41}
42
43static int rzg2l_gpio_set_value(struct udevice *dev, unsigned int offset,
44				int value)
45{
46	const struct rzg2l_pfc_data *data =
47		(const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
48	const u32 port = RZG2L_PINMUX_TO_PORT(offset);
49	const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
50
51	rzg2l_gpio_set(data, port, pin, (bool)value);
52	return 0;
53}
54
55static void rzg2l_gpio_set_direction(const struct rzg2l_pfc_data *data,
56				     u32 port, u8 pin, bool output)
57{
58	clrsetbits_le16(data->base + PM(port), PM_MASK << (pin * 2),
59			(output ? PM_OUTPUT : PM_INPUT) << (pin * 2));
60}
61
62static int rzg2l_gpio_direction_input(struct udevice *dev, unsigned int offset)
63{
64	const struct rzg2l_pfc_data *data =
65		(const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
66	const u32 port = RZG2L_PINMUX_TO_PORT(offset);
67	const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
68
69	rzg2l_gpio_set_direction(data, port, pin, false);
70	return 0;
71}
72
73static int rzg2l_gpio_direction_output(struct udevice *dev, unsigned int offset,
74				       int value)
75{
76	const struct rzg2l_pfc_data *data =
77		(const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
78	const u32 port = RZG2L_PINMUX_TO_PORT(offset);
79	const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
80
81	rzg2l_gpio_set(data, port, pin, (bool)value);
82	rzg2l_gpio_set_direction(data, port, pin, true);
83	return 0;
84}
85
86static int rzg2l_gpio_request(struct udevice *dev, unsigned int offset,
87			      const char *label)
88{
89	const struct rzg2l_pfc_data *data =
90		(const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
91	const u32 port = RZG2L_PINMUX_TO_PORT(offset);
92	const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
93
94	if (!rzg2l_port_validate(data, port, pin)) {
95		dev_err(dev, "Invalid GPIO %u:%u\n", port, pin);
96		return -EINVAL;
97	}
98
99	/* Select GPIO mode in PMC Register */
100	clrbits_8(data->base + PMC(port), BIT(pin));
101
102	return 0;
103}
104
105static int rzg2l_gpio_get_function(struct udevice *dev, unsigned int offset)
106{
107	const struct rzg2l_pfc_data *data =
108		(const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
109	const u32 port = RZG2L_PINMUX_TO_PORT(offset);
110	const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
111	u16 pm_state;
112	u8 pmc_state;
113
114	if (!rzg2l_port_validate(data, port, pin)) {
115		/* This offset does not correspond to a valid GPIO pin. */
116		return -ENOENT;
117	}
118
119	/* Check if the pin is in GPIO or function mode. */
120	pmc_state = readb(data->base + PMC(port)) & BIT(pin);
121	if (pmc_state)
122		return GPIOF_FUNC;
123
124	/* Check the pin direction. */
125	pm_state = (readw(data->base + PM(port)) >> (pin * 2)) & PM_MASK;
126	switch (pm_state) {
127	case PM_INPUT:
128		return GPIOF_INPUT;
129	case PM_OUTPUT:
130	case PM_OUTPUT_IEN:
131		return GPIOF_OUTPUT;
132	default:	/* PM_HIGH_Z */
133		return GPIOF_UNUSED;
134	}
135}
136
137static const struct dm_gpio_ops rzg2l_gpio_ops = {
138	.direction_input	= rzg2l_gpio_direction_input,
139	.direction_output	= rzg2l_gpio_direction_output,
140	.get_value		= rzg2l_gpio_get_value,
141	.set_value		= rzg2l_gpio_set_value,
142	.request		= rzg2l_gpio_request,
143	.get_function		= rzg2l_gpio_get_function,
144};
145
146static int rzg2l_gpio_probe(struct udevice *dev)
147{
148	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
149	struct ofnode_phandle_args args;
150	int ret;
151
152	uc_priv->bank_name = "rzg2l-pfc-gpio";
153	ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
154					     NULL, 3, 0, &args);
155	if (ret < 0) {
156		dev_err(dev, "Failed to parse gpio-ranges: %d\n", ret);
157		return -EINVAL;
158	}
159
160	uc_priv->gpio_count = args.args[2];
161	return rzg2l_pfc_enable(dev);
162}
163
164U_BOOT_DRIVER(rzg2l_pfc_gpio) = {
165	.name		= "rzg2l-pfc-gpio",
166	.id		= UCLASS_GPIO,
167	.ops		= &rzg2l_gpio_ops,
168	.probe		= rzg2l_gpio_probe,
169};
170