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