xref: /linux/drivers/pinctrl/realtek/pinctrl-rtd.c (revision 03c11eb3b16dc0058589751dfd91f254be2be613)
1e99ce780STzuyi Chang // SPDX-License-Identifier: GPL-2.0-or-later
2e99ce780STzuyi Chang /*
3e99ce780STzuyi Chang  * Realtek DHC pin controller driver
4e99ce780STzuyi Chang  *
5e99ce780STzuyi Chang  * Copyright (c) 2023 Realtek Semiconductor Corp.
6e99ce780STzuyi Chang  */
7e99ce780STzuyi Chang 
8e99ce780STzuyi Chang #include <linux/bitops.h>
9e99ce780STzuyi Chang #include <linux/io.h>
10e99ce780STzuyi Chang #include <linux/module.h>
11e99ce780STzuyi Chang #include <linux/of.h>
12e99ce780STzuyi Chang #include <linux/of_address.h>
13e99ce780STzuyi Chang #include <linux/pinctrl/machine.h>
14e99ce780STzuyi Chang #include <linux/pinctrl/pinconf.h>
15e99ce780STzuyi Chang #include <linux/pinctrl/pinconf-generic.h>
16e99ce780STzuyi Chang #include <linux/pinctrl/pinctrl.h>
17e99ce780STzuyi Chang #include <linux/pinctrl/pinmux.h>
18e99ce780STzuyi Chang #include <linux/platform_device.h>
19e99ce780STzuyi Chang #include <linux/seq_file.h>
20e99ce780STzuyi Chang #include <linux/regmap.h>
21e99ce780STzuyi Chang #include <linux/slab.h>
22e99ce780STzuyi Chang #include "../core.h"
23e99ce780STzuyi Chang #include "../pinctrl-utils.h"
24e99ce780STzuyi Chang #include "pinctrl-rtd.h"
25e99ce780STzuyi Chang 
26e99ce780STzuyi Chang struct rtd_pinctrl {
27e99ce780STzuyi Chang 	struct device *dev;
28e99ce780STzuyi Chang 	struct pinctrl_dev *pcdev;
29e99ce780STzuyi Chang 	void __iomem *base;
30e99ce780STzuyi Chang 	struct pinctrl_desc desc;
31e99ce780STzuyi Chang 	const struct rtd_pinctrl_desc *info;
32e99ce780STzuyi Chang 	struct regmap *regmap_pinctrl;
33e99ce780STzuyi Chang };
34e99ce780STzuyi Chang 
35e99ce780STzuyi Chang /* custom pinconf parameters */
36e99ce780STzuyi Chang #define RTD_DRIVE_STRENGH_P (PIN_CONFIG_END + 1)
37e99ce780STzuyi Chang #define RTD_DRIVE_STRENGH_N (PIN_CONFIG_END + 2)
38e99ce780STzuyi Chang #define RTD_DUTY_CYCLE (PIN_CONFIG_END + 3)
39e99ce780STzuyi Chang 
40e99ce780STzuyi Chang static const struct pinconf_generic_params rtd_custom_bindings[] = {
41e99ce780STzuyi Chang 	{"realtek,drive-strength-p", RTD_DRIVE_STRENGH_P, 0},
42e99ce780STzuyi Chang 	{"realtek,drive-strength-n", RTD_DRIVE_STRENGH_N, 0},
43e99ce780STzuyi Chang 	{"realtek,duty-cycle", RTD_DUTY_CYCLE, 0},
44e99ce780STzuyi Chang };
45e99ce780STzuyi Chang 
rtd_pinctrl_get_groups_count(struct pinctrl_dev * pcdev)46e99ce780STzuyi Chang static int rtd_pinctrl_get_groups_count(struct pinctrl_dev *pcdev)
47e99ce780STzuyi Chang {
48e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
49e99ce780STzuyi Chang 
50e99ce780STzuyi Chang 	return data->info->num_groups;
51e99ce780STzuyi Chang }
52e99ce780STzuyi Chang 
rtd_pinctrl_get_group_name(struct pinctrl_dev * pcdev,unsigned int selector)53e99ce780STzuyi Chang static const char *rtd_pinctrl_get_group_name(struct pinctrl_dev *pcdev,
54e99ce780STzuyi Chang 					      unsigned int selector)
55e99ce780STzuyi Chang {
56e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
57e99ce780STzuyi Chang 
58e99ce780STzuyi Chang 	return data->info->groups[selector].name;
59e99ce780STzuyi Chang }
60e99ce780STzuyi Chang 
rtd_pinctrl_get_group_pins(struct pinctrl_dev * pcdev,unsigned int selector,const unsigned int ** pins,unsigned int * num_pins)61e99ce780STzuyi Chang static int rtd_pinctrl_get_group_pins(struct pinctrl_dev *pcdev,
62e99ce780STzuyi Chang 				      unsigned int selector,
63e99ce780STzuyi Chang 				      const unsigned int **pins,
64e99ce780STzuyi Chang 				      unsigned int *num_pins)
65e99ce780STzuyi Chang {
66e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
67e99ce780STzuyi Chang 
68e99ce780STzuyi Chang 	*pins = data->info->groups[selector].pins;
69e99ce780STzuyi Chang 	*num_pins = data->info->groups[selector].num_pins;
70e99ce780STzuyi Chang 
71e99ce780STzuyi Chang 	return 0;
72e99ce780STzuyi Chang }
73e99ce780STzuyi Chang 
rtd_pinctrl_dbg_show(struct pinctrl_dev * pcdev,struct seq_file * s,unsigned int offset)74e99ce780STzuyi Chang static void rtd_pinctrl_dbg_show(struct pinctrl_dev *pcdev,
75e99ce780STzuyi Chang 				 struct seq_file *s,
76e99ce780STzuyi Chang 				 unsigned int offset)
77e99ce780STzuyi Chang {
78e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
79e99ce780STzuyi Chang 	const struct rtd_pin_desc *mux = &data->info->muxes[offset];
80e99ce780STzuyi Chang 	const struct rtd_pin_mux_desc *func;
81e99ce780STzuyi Chang 	u32 val;
82e99ce780STzuyi Chang 	u32 mask;
83e99ce780STzuyi Chang 	u32 pin_val;
84e99ce780STzuyi Chang 	int is_map;
85e99ce780STzuyi Chang 
86e99ce780STzuyi Chang 	if (!mux->name) {
87e99ce780STzuyi Chang 		seq_puts(s, "[not defined]");
88e99ce780STzuyi Chang 		return;
89e99ce780STzuyi Chang 	}
90e99ce780STzuyi Chang 	val = readl_relaxed(data->base + mux->mux_offset);
91e99ce780STzuyi Chang 	mask = mux->mux_mask;
92e99ce780STzuyi Chang 	pin_val = val & mask;
93e99ce780STzuyi Chang 
94e99ce780STzuyi Chang 	is_map = 0;
95e99ce780STzuyi Chang 	func = &mux->functions[0];
96e99ce780STzuyi Chang 	seq_puts(s, "function: ");
97e99ce780STzuyi Chang 	while (func->name) {
98e99ce780STzuyi Chang 		if (func->mux_value == pin_val) {
99e99ce780STzuyi Chang 			is_map = 1;
100e99ce780STzuyi Chang 			seq_printf(s, "[%s] ", func->name);
101e99ce780STzuyi Chang 		} else {
102e99ce780STzuyi Chang 			seq_printf(s, "%s ", func->name);
103e99ce780STzuyi Chang 		}
104e99ce780STzuyi Chang 		func++;
105e99ce780STzuyi Chang 	}
106e99ce780STzuyi Chang 	if (!is_map)
107e99ce780STzuyi Chang 		seq_puts(s, "[not defined]");
108e99ce780STzuyi Chang }
109e99ce780STzuyi Chang 
110e99ce780STzuyi Chang static const struct pinctrl_ops rtd_pinctrl_ops = {
111e99ce780STzuyi Chang 	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
112e99ce780STzuyi Chang 	.dt_free_map = pinctrl_utils_free_map,
113e99ce780STzuyi Chang 	.get_groups_count = rtd_pinctrl_get_groups_count,
114e99ce780STzuyi Chang 	.get_group_name = rtd_pinctrl_get_group_name,
115e99ce780STzuyi Chang 	.get_group_pins = rtd_pinctrl_get_group_pins,
116e99ce780STzuyi Chang 	.pin_dbg_show = rtd_pinctrl_dbg_show,
117e99ce780STzuyi Chang };
118e99ce780STzuyi Chang 
rtd_pinctrl_get_functions_count(struct pinctrl_dev * pcdev)119e99ce780STzuyi Chang static int rtd_pinctrl_get_functions_count(struct pinctrl_dev *pcdev)
120e99ce780STzuyi Chang {
121e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
122e99ce780STzuyi Chang 
123e99ce780STzuyi Chang 	return data->info->num_functions;
124e99ce780STzuyi Chang }
125e99ce780STzuyi Chang 
rtd_pinctrl_get_function_name(struct pinctrl_dev * pcdev,unsigned int selector)126e99ce780STzuyi Chang static const char *rtd_pinctrl_get_function_name(struct pinctrl_dev *pcdev,
127e99ce780STzuyi Chang 						 unsigned int selector)
128e99ce780STzuyi Chang {
129e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
130e99ce780STzuyi Chang 
131e99ce780STzuyi Chang 	return data->info->functions[selector].name;
132e99ce780STzuyi Chang }
133e99ce780STzuyi Chang 
rtd_pinctrl_get_function_groups(struct pinctrl_dev * pcdev,unsigned int selector,const char * const ** groups,unsigned int * const num_groups)134e99ce780STzuyi Chang static int rtd_pinctrl_get_function_groups(struct pinctrl_dev *pcdev,
135e99ce780STzuyi Chang 					   unsigned int selector,
136e99ce780STzuyi Chang 					   const char * const **groups,
137e99ce780STzuyi Chang 					   unsigned int * const num_groups)
138e99ce780STzuyi Chang {
139e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
140e99ce780STzuyi Chang 
141e99ce780STzuyi Chang 	*groups = data->info->functions[selector].groups;
142e99ce780STzuyi Chang 	*num_groups = data->info->functions[selector].num_groups;
143e99ce780STzuyi Chang 
144e99ce780STzuyi Chang 	return 0;
145e99ce780STzuyi Chang }
146e99ce780STzuyi Chang 
rtd_pinctrl_find_mux(struct rtd_pinctrl * data,unsigned int pin)147e99ce780STzuyi Chang static const struct rtd_pin_desc *rtd_pinctrl_find_mux(struct rtd_pinctrl *data, unsigned int pin)
148e99ce780STzuyi Chang {
149*38a285d5STzuyi Chang 	if (data->info->muxes[pin].name)
150e99ce780STzuyi Chang 		return &data->info->muxes[pin];
151e99ce780STzuyi Chang 
152e99ce780STzuyi Chang 	return NULL;
153e99ce780STzuyi Chang }
154e99ce780STzuyi Chang 
rtd_pinctrl_set_one_mux(struct pinctrl_dev * pcdev,unsigned int pin,const char * func_name)155e99ce780STzuyi Chang static int rtd_pinctrl_set_one_mux(struct pinctrl_dev *pcdev,
156e99ce780STzuyi Chang 				   unsigned int pin, const char *func_name)
157e99ce780STzuyi Chang {
158e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
159e99ce780STzuyi Chang 	const struct rtd_pin_desc *mux;
160e99ce780STzuyi Chang 	int ret = 0;
161e99ce780STzuyi Chang 	int i;
162e99ce780STzuyi Chang 
163e99ce780STzuyi Chang 	mux = rtd_pinctrl_find_mux(data, pin);
164e99ce780STzuyi Chang 	if (!mux)
165e99ce780STzuyi Chang 		return 0;
166e99ce780STzuyi Chang 
167e99ce780STzuyi Chang 	if (!mux->functions) {
1680aa5369fSLinus Walleij 		if (!mux->name)
1690aa5369fSLinus Walleij 			dev_err(pcdev->dev, "NULL pin has no functions\n");
1700aa5369fSLinus Walleij 		else
171e99ce780STzuyi Chang 			dev_err(pcdev->dev, "No functions available for pin %s\n", mux->name);
172e99ce780STzuyi Chang 		return -ENOTSUPP;
173e99ce780STzuyi Chang 	}
174e99ce780STzuyi Chang 
175e99ce780STzuyi Chang 	for (i = 0; mux->functions[i].name; i++) {
176e99ce780STzuyi Chang 		if (strcmp(mux->functions[i].name, func_name) != 0)
177e99ce780STzuyi Chang 			continue;
178e99ce780STzuyi Chang 		ret = regmap_update_bits(data->regmap_pinctrl, mux->mux_offset, mux->mux_mask,
179e99ce780STzuyi Chang 					mux->functions[i].mux_value);
180e99ce780STzuyi Chang 		return ret;
181e99ce780STzuyi Chang 	}
182e99ce780STzuyi Chang 
1830aa5369fSLinus Walleij 	if (!mux->name) {
1840aa5369fSLinus Walleij 		dev_err(pcdev->dev, "NULL pin provided for function %s\n", func_name);
1850aa5369fSLinus Walleij 		return -EINVAL;
1860aa5369fSLinus Walleij 	}
1870aa5369fSLinus Walleij 
188e99ce780STzuyi Chang 	dev_err(pcdev->dev, "No function %s available for pin %s\n", func_name, mux->name);
189e99ce780STzuyi Chang 
190e99ce780STzuyi Chang 	return -EINVAL;
191e99ce780STzuyi Chang }
192e99ce780STzuyi Chang 
rtd_pinctrl_set_mux(struct pinctrl_dev * pcdev,unsigned int function,unsigned int group)193e99ce780STzuyi Chang static int rtd_pinctrl_set_mux(struct pinctrl_dev *pcdev,
194e99ce780STzuyi Chang 			       unsigned int function, unsigned int group)
195e99ce780STzuyi Chang {
196e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
197e99ce780STzuyi Chang 	const unsigned int *pins;
198e99ce780STzuyi Chang 	unsigned int num_pins;
199e99ce780STzuyi Chang 	const char *func_name;
200e99ce780STzuyi Chang 	const char *group_name;
201e99ce780STzuyi Chang 	int i, ret;
202e99ce780STzuyi Chang 
203e99ce780STzuyi Chang 	func_name = data->info->functions[function].name;
204e99ce780STzuyi Chang 	group_name = data->info->groups[group].name;
205e99ce780STzuyi Chang 
206e99ce780STzuyi Chang 	ret = rtd_pinctrl_get_group_pins(pcdev, group, &pins, &num_pins);
207e99ce780STzuyi Chang 	if (ret) {
208e99ce780STzuyi Chang 		dev_err(pcdev->dev, "Getting pins for group %s failed\n", group_name);
209e99ce780STzuyi Chang 		return ret;
210e99ce780STzuyi Chang 	}
211e99ce780STzuyi Chang 
212e99ce780STzuyi Chang 	for (i = 0; i < num_pins; i++) {
213e99ce780STzuyi Chang 		ret = rtd_pinctrl_set_one_mux(pcdev, pins[i], func_name);
214e99ce780STzuyi Chang 		if (ret)
215e99ce780STzuyi Chang 			return ret;
216e99ce780STzuyi Chang 	}
217e99ce780STzuyi Chang 
218e99ce780STzuyi Chang 	return 0;
219e99ce780STzuyi Chang }
220e99ce780STzuyi Chang 
rtd_pinctrl_gpio_request_enable(struct pinctrl_dev * pcdev,struct pinctrl_gpio_range * range,unsigned int offset)221e99ce780STzuyi Chang static int rtd_pinctrl_gpio_request_enable(struct pinctrl_dev *pcdev,
222e99ce780STzuyi Chang 					   struct pinctrl_gpio_range *range,
223e99ce780STzuyi Chang 					   unsigned int offset)
224e99ce780STzuyi Chang {
225e99ce780STzuyi Chang 	return rtd_pinctrl_set_one_mux(pcdev, offset, "gpio");
226e99ce780STzuyi Chang }
227e99ce780STzuyi Chang 
228e99ce780STzuyi Chang static const struct pinmux_ops rtd_pinmux_ops = {
229e99ce780STzuyi Chang 	.get_functions_count = rtd_pinctrl_get_functions_count,
230e99ce780STzuyi Chang 	.get_function_name = rtd_pinctrl_get_function_name,
231e99ce780STzuyi Chang 	.get_function_groups = rtd_pinctrl_get_function_groups,
232e99ce780STzuyi Chang 	.set_mux = rtd_pinctrl_set_mux,
233e99ce780STzuyi Chang 	.gpio_request_enable = rtd_pinctrl_gpio_request_enable,
234e99ce780STzuyi Chang };
235e99ce780STzuyi Chang 
236e99ce780STzuyi Chang static const struct pinctrl_pin_desc
rtd_pinctrl_get_pin_by_number(struct rtd_pinctrl * data,int number)237e99ce780STzuyi Chang 	*rtd_pinctrl_get_pin_by_number(struct rtd_pinctrl *data, int number)
238e99ce780STzuyi Chang {
239e99ce780STzuyi Chang 	int i;
240e99ce780STzuyi Chang 
241e99ce780STzuyi Chang 	for (i = 0; i < data->info->num_pins; i++) {
242e99ce780STzuyi Chang 		if (data->info->pins[i].number == number)
243e99ce780STzuyi Chang 			return &data->info->pins[i];
244e99ce780STzuyi Chang 	}
245e99ce780STzuyi Chang 
246e99ce780STzuyi Chang 	return NULL;
247e99ce780STzuyi Chang }
248e99ce780STzuyi Chang 
249e99ce780STzuyi Chang static const struct rtd_pin_config_desc
rtd_pinctrl_find_config(struct rtd_pinctrl * data,unsigned int pin)250e99ce780STzuyi Chang 	*rtd_pinctrl_find_config(struct rtd_pinctrl *data, unsigned int pin)
251e99ce780STzuyi Chang {
252*38a285d5STzuyi Chang 	if (data->info->configs[pin].name)
253e99ce780STzuyi Chang 		return &data->info->configs[pin];
254e99ce780STzuyi Chang 
255e99ce780STzuyi Chang 	return NULL;
256e99ce780STzuyi Chang }
257e99ce780STzuyi Chang 
rtd_pinctrl_find_sconfig(struct rtd_pinctrl * data,unsigned int pin)258e99ce780STzuyi Chang static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pinctrl *data,
259e99ce780STzuyi Chang 								   unsigned int pin)
260e99ce780STzuyi Chang {
261e99ce780STzuyi Chang 	int i;
262e99ce780STzuyi Chang 	const struct pinctrl_pin_desc *pin_desc;
263e99ce780STzuyi Chang 	const char *pin_name;
264e99ce780STzuyi Chang 
265e99ce780STzuyi Chang 	pin_desc = rtd_pinctrl_get_pin_by_number(data, pin);
266e99ce780STzuyi Chang 	if (!pin_desc)
267e99ce780STzuyi Chang 		return NULL;
268e99ce780STzuyi Chang 
269e99ce780STzuyi Chang 	pin_name = pin_desc->name;
270e99ce780STzuyi Chang 
271e99ce780STzuyi Chang 	for (i = 0; i < data->info->num_sconfigs; i++) {
272e99ce780STzuyi Chang 		if (strcmp(data->info->sconfigs[i].name, pin_name) == 0)
273e99ce780STzuyi Chang 			return &data->info->sconfigs[i];
274e99ce780STzuyi Chang 	}
275e99ce780STzuyi Chang 
276e99ce780STzuyi Chang 	return NULL;
277e99ce780STzuyi Chang }
278e99ce780STzuyi Chang 
rtd_pconf_parse_conf(struct rtd_pinctrl * data,unsigned int pinnr,enum pin_config_param param,enum pin_config_param arg)279e99ce780STzuyi Chang static int rtd_pconf_parse_conf(struct rtd_pinctrl *data,
280e99ce780STzuyi Chang 				unsigned int pinnr,
281e99ce780STzuyi Chang 				enum pin_config_param param,
282e99ce780STzuyi Chang 				enum pin_config_param arg)
283e99ce780STzuyi Chang {
284e99ce780STzuyi Chang 	const struct rtd_pin_config_desc *config_desc;
285e99ce780STzuyi Chang 	const struct rtd_pin_sconfig_desc *sconfig_desc;
286e99ce780STzuyi Chang 	u8 set_val = 0;
287e99ce780STzuyi Chang 	u16 strength;
288e99ce780STzuyi Chang 	u32 val;
289e99ce780STzuyi Chang 	u32 mask;
290e99ce780STzuyi Chang 	u32 pulsel_off, pulen_off, smt_off, curr_off, pow_off, reg_off, p_off, n_off;
291e99ce780STzuyi Chang 	const char *name = data->info->pins[pinnr].name;
292e99ce780STzuyi Chang 	int ret = 0;
293e99ce780STzuyi Chang 
294e99ce780STzuyi Chang 	config_desc = rtd_pinctrl_find_config(data, pinnr);
295e99ce780STzuyi Chang 	if (!config_desc) {
296e99ce780STzuyi Chang 		dev_err(data->dev, "Not support pin config for pin: %s\n", name);
297e99ce780STzuyi Chang 		return -ENOTSUPP;
298e99ce780STzuyi Chang 	}
299e99ce780STzuyi Chang 	switch ((u32)param) {
300e99ce780STzuyi Chang 	case PIN_CONFIG_INPUT_SCHMITT:
301e99ce780STzuyi Chang 	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
302e99ce780STzuyi Chang 		if (config_desc->smt_offset == NA) {
303e99ce780STzuyi Chang 			dev_err(data->dev, "Not support input schmitt for pin: %s\n", name);
304e99ce780STzuyi Chang 			return -ENOTSUPP;
305e99ce780STzuyi Chang 		}
306e99ce780STzuyi Chang 		smt_off = config_desc->base_bit + config_desc->smt_offset;
307e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
308e99ce780STzuyi Chang 		set_val = arg;
309e99ce780STzuyi Chang 
310e99ce780STzuyi Chang 		mask = BIT(smt_off);
311e99ce780STzuyi Chang 		val = set_val ? BIT(smt_off) : 0;
312e99ce780STzuyi Chang 		break;
313e99ce780STzuyi Chang 
314e99ce780STzuyi Chang 	case PIN_CONFIG_DRIVE_PUSH_PULL:
315e99ce780STzuyi Chang 		if (config_desc->pud_en_offset == NA) {
316e99ce780STzuyi Chang 			dev_err(data->dev, "Not support push pull for pin: %s\n", name);
317e99ce780STzuyi Chang 			return -ENOTSUPP;
318e99ce780STzuyi Chang 		}
319e99ce780STzuyi Chang 		pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
320e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
321e99ce780STzuyi Chang 
322e99ce780STzuyi Chang 		mask =  BIT(pulen_off);
323e99ce780STzuyi Chang 		val = 0;
324e99ce780STzuyi Chang 		break;
325e99ce780STzuyi Chang 
326e99ce780STzuyi Chang 	case PIN_CONFIG_BIAS_DISABLE:
327e99ce780STzuyi Chang 		if (config_desc->pud_en_offset == NA) {
328e99ce780STzuyi Chang 			dev_err(data->dev, "Not support bias disable for pin: %s\n", name);
329e99ce780STzuyi Chang 			return -ENOTSUPP;
330e99ce780STzuyi Chang 		}
331e99ce780STzuyi Chang 		pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
332e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
333e99ce780STzuyi Chang 
334e99ce780STzuyi Chang 		mask =  BIT(pulen_off);
335e99ce780STzuyi Chang 		val = 0;
336e99ce780STzuyi Chang 		break;
337e99ce780STzuyi Chang 
338e99ce780STzuyi Chang 	case PIN_CONFIG_BIAS_PULL_UP:
339e99ce780STzuyi Chang 		if (config_desc->pud_en_offset == NA) {
340e99ce780STzuyi Chang 			dev_err(data->dev, "Not support bias pull up for pin:%s\n", name);
341e99ce780STzuyi Chang 			return -ENOTSUPP;
342e99ce780STzuyi Chang 		}
343e99ce780STzuyi Chang 		pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
344e99ce780STzuyi Chang 		pulsel_off = config_desc->base_bit + config_desc->pud_sel_offset;
345e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
346e99ce780STzuyi Chang 
347e99ce780STzuyi Chang 		mask = BIT(pulen_off) | BIT(pulsel_off);
348e99ce780STzuyi Chang 		val = mask;
349e99ce780STzuyi Chang 		break;
350e99ce780STzuyi Chang 
351e99ce780STzuyi Chang 	case PIN_CONFIG_BIAS_PULL_DOWN:
352e99ce780STzuyi Chang 		if (config_desc->pud_en_offset == NA) {
353e99ce780STzuyi Chang 			dev_err(data->dev, "Not support bias pull down for pin: %s\n", name);
354e99ce780STzuyi Chang 			return -ENOTSUPP;
355e99ce780STzuyi Chang 		}
356e99ce780STzuyi Chang 		pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
357e99ce780STzuyi Chang 		pulsel_off = config_desc->base_bit + config_desc->pud_sel_offset;
358e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
359e99ce780STzuyi Chang 
360e99ce780STzuyi Chang 		mask = BIT(pulen_off) | BIT(pulsel_off);
361e99ce780STzuyi Chang 		val = BIT(pulen_off);
362e99ce780STzuyi Chang 		break;
363e99ce780STzuyi Chang 
364e99ce780STzuyi Chang 	case PIN_CONFIG_DRIVE_STRENGTH:
365e99ce780STzuyi Chang 		curr_off = config_desc->base_bit + config_desc->curr_offset;
366e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
367e99ce780STzuyi Chang 		strength = arg;
368e99ce780STzuyi Chang 		val = 0;
369e99ce780STzuyi Chang 		switch (config_desc->curr_type) {
370e99ce780STzuyi Chang 		case PADDRI_4_8:
371e99ce780STzuyi Chang 			if (strength == 4)
372e99ce780STzuyi Chang 				val = 0;
373e99ce780STzuyi Chang 			else if (strength == 8)
374e99ce780STzuyi Chang 				val = BIT(curr_off);
375e99ce780STzuyi Chang 			else
376e99ce780STzuyi Chang 				return -EINVAL;
377e99ce780STzuyi Chang 			break;
378e99ce780STzuyi Chang 		case PADDRI_2_4:
379e99ce780STzuyi Chang 			if (strength == 2)
380e99ce780STzuyi Chang 				val = 0;
381e99ce780STzuyi Chang 			else if (strength == 4)
382e99ce780STzuyi Chang 				val = BIT(curr_off);
383e99ce780STzuyi Chang 			else
384e99ce780STzuyi Chang 				return -EINVAL;
385e99ce780STzuyi Chang 			break;
386e99ce780STzuyi Chang 		case NA:
387e99ce780STzuyi Chang 			dev_err(data->dev, "Not support drive strength for pin: %s\n", name);
388e99ce780STzuyi Chang 			return -ENOTSUPP;
389e99ce780STzuyi Chang 		default:
390e99ce780STzuyi Chang 			return -EINVAL;
391e99ce780STzuyi Chang 		}
392e99ce780STzuyi Chang 		mask = BIT(curr_off);
393e99ce780STzuyi Chang 		break;
394e99ce780STzuyi Chang 
395e99ce780STzuyi Chang 	case PIN_CONFIG_POWER_SOURCE:
396e99ce780STzuyi Chang 		if (config_desc->power_offset == NA) {
397e99ce780STzuyi Chang 			dev_err(data->dev, "Not support power source for pin: %s\n", name);
398e99ce780STzuyi Chang 			return -ENOTSUPP;
399e99ce780STzuyi Chang 		}
400e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
401e99ce780STzuyi Chang 		pow_off = config_desc->base_bit + config_desc->power_offset;
402e99ce780STzuyi Chang 		if (pow_off >= 32) {
403e99ce780STzuyi Chang 			reg_off += 0x4;
404e99ce780STzuyi Chang 			pow_off -= 32;
405e99ce780STzuyi Chang 		}
406e99ce780STzuyi Chang 		set_val = arg;
407e99ce780STzuyi Chang 		mask = BIT(pow_off);
408e99ce780STzuyi Chang 		val = set_val ? mask : 0;
409e99ce780STzuyi Chang 		break;
410e99ce780STzuyi Chang 
411e99ce780STzuyi Chang 	case RTD_DRIVE_STRENGH_P:
412e99ce780STzuyi Chang 		sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr);
413e99ce780STzuyi Chang 		if (!sconfig_desc) {
414e99ce780STzuyi Chang 			dev_err(data->dev, "Not support P driving for pin: %s\n", name);
415e99ce780STzuyi Chang 			return -ENOTSUPP;
416e99ce780STzuyi Chang 		}
417e99ce780STzuyi Chang 		set_val = arg;
418e99ce780STzuyi Chang 		reg_off = sconfig_desc->reg_offset;
419e99ce780STzuyi Chang 		p_off = sconfig_desc->pdrive_offset;
420e99ce780STzuyi Chang 		if (p_off >= 32) {
421e99ce780STzuyi Chang 			reg_off += 0x4;
422e99ce780STzuyi Chang 			p_off -= 32;
423e99ce780STzuyi Chang 		}
424e99ce780STzuyi Chang 		mask = GENMASK(p_off + sconfig_desc->pdrive_maskbits - 1, p_off);
425e99ce780STzuyi Chang 		val = set_val << p_off;
426e99ce780STzuyi Chang 		break;
427e99ce780STzuyi Chang 
428e99ce780STzuyi Chang 	case RTD_DRIVE_STRENGH_N:
429e99ce780STzuyi Chang 		sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr);
430e99ce780STzuyi Chang 		if (!sconfig_desc) {
431e99ce780STzuyi Chang 			dev_err(data->dev, "Not support N driving for pin: %s\n", name);
432e99ce780STzuyi Chang 			return -ENOTSUPP;
433e99ce780STzuyi Chang 		}
434e99ce780STzuyi Chang 		set_val = arg;
435e99ce780STzuyi Chang 		reg_off = sconfig_desc->reg_offset;
436e99ce780STzuyi Chang 		n_off = sconfig_desc->ndrive_offset;
437e99ce780STzuyi Chang 		if (n_off >= 32) {
438e99ce780STzuyi Chang 			reg_off += 0x4;
439e99ce780STzuyi Chang 			n_off -= 32;
440e99ce780STzuyi Chang 		}
441e99ce780STzuyi Chang 		mask = GENMASK(n_off + sconfig_desc->ndrive_maskbits - 1, n_off);
442e99ce780STzuyi Chang 		val = set_val << n_off;
443e99ce780STzuyi Chang 		break;
444e99ce780STzuyi Chang 
445e99ce780STzuyi Chang 	case RTD_DUTY_CYCLE:
446e99ce780STzuyi Chang 		sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr);
447e99ce780STzuyi Chang 		if (!sconfig_desc || sconfig_desc->dcycle_offset == NA) {
448e99ce780STzuyi Chang 			dev_err(data->dev, "Not support duty cycle for pin: %s\n", name);
449e99ce780STzuyi Chang 			return -ENOTSUPP;
450e99ce780STzuyi Chang 		}
451e99ce780STzuyi Chang 		set_val = arg;
452e99ce780STzuyi Chang 		reg_off = config_desc->reg_offset;
453e99ce780STzuyi Chang 		mask = GENMASK(sconfig_desc->dcycle_offset +
454e99ce780STzuyi Chang 		sconfig_desc->dcycle_maskbits - 1, sconfig_desc->dcycle_offset);
455e99ce780STzuyi Chang 		val = set_val << sconfig_desc->dcycle_offset;
456e99ce780STzuyi Chang 		break;
457e99ce780STzuyi Chang 
458e99ce780STzuyi Chang 	default:
459e99ce780STzuyi Chang 		dev_err(data->dev, "unsupported pinconf: %d\n", (u32)param);
460e99ce780STzuyi Chang 		return -EINVAL;
461e99ce780STzuyi Chang 	}
462e99ce780STzuyi Chang 
463e99ce780STzuyi Chang 	ret = regmap_update_bits(data->regmap_pinctrl, reg_off, mask, val);
464e99ce780STzuyi Chang 	if (ret)
465e99ce780STzuyi Chang 		dev_err(data->dev, "could not update pinconf(%d) for pin(%s)\n", (u32)param, name);
466e99ce780STzuyi Chang 
467e99ce780STzuyi Chang 	return ret;
468e99ce780STzuyi Chang }
469e99ce780STzuyi Chang 
rtd_pin_config_get(struct pinctrl_dev * pcdev,unsigned int pinnr,unsigned long * config)470e99ce780STzuyi Chang static int rtd_pin_config_get(struct pinctrl_dev *pcdev, unsigned int pinnr,
471e99ce780STzuyi Chang 			      unsigned long *config)
472e99ce780STzuyi Chang {
473e99ce780STzuyi Chang 	unsigned int param = pinconf_to_config_param(*config);
474e99ce780STzuyi Chang 	unsigned int arg = 0;
475e99ce780STzuyi Chang 
476e99ce780STzuyi Chang 	switch (param) {
477e99ce780STzuyi Chang 	default:
478e99ce780STzuyi Chang 		return -ENOTSUPP;
479e99ce780STzuyi Chang 	}
480e99ce780STzuyi Chang 
481e99ce780STzuyi Chang 	*config = pinconf_to_config_packed(param, arg);
482e99ce780STzuyi Chang 	return 0;
483e99ce780STzuyi Chang }
484e99ce780STzuyi Chang 
rtd_pin_config_set(struct pinctrl_dev * pcdev,unsigned int pinnr,unsigned long * configs,unsigned int num_configs)485e99ce780STzuyi Chang static int rtd_pin_config_set(struct pinctrl_dev *pcdev, unsigned int pinnr,
486e99ce780STzuyi Chang 			      unsigned long *configs, unsigned int num_configs)
487e99ce780STzuyi Chang {
488e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
489e99ce780STzuyi Chang 	int i;
490e99ce780STzuyi Chang 	int ret = 0;
491e99ce780STzuyi Chang 
492e99ce780STzuyi Chang 	for (i = 0; i < num_configs; i++) {
493e99ce780STzuyi Chang 		ret = rtd_pconf_parse_conf(data, pinnr,
494e99ce780STzuyi Chang 					   pinconf_to_config_param(configs[i]),
495e99ce780STzuyi Chang 					   pinconf_to_config_argument(configs[i]));
496e99ce780STzuyi Chang 		if (ret < 0)
497e99ce780STzuyi Chang 			return ret;
498e99ce780STzuyi Chang 	}
499e99ce780STzuyi Chang 
500e99ce780STzuyi Chang 	return 0;
501e99ce780STzuyi Chang }
502e99ce780STzuyi Chang 
rtd_pin_config_group_set(struct pinctrl_dev * pcdev,unsigned int group,unsigned long * configs,unsigned int num_configs)503e99ce780STzuyi Chang static int rtd_pin_config_group_set(struct pinctrl_dev *pcdev, unsigned int group,
504e99ce780STzuyi Chang 				    unsigned long *configs, unsigned int num_configs)
505e99ce780STzuyi Chang {
506e99ce780STzuyi Chang 	struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
507e99ce780STzuyi Chang 	const unsigned int *pins;
508e99ce780STzuyi Chang 	unsigned int num_pins;
509e99ce780STzuyi Chang 	const char *group_name;
510e99ce780STzuyi Chang 	int i, ret;
511e99ce780STzuyi Chang 
512e99ce780STzuyi Chang 	group_name = data->info->groups[group].name;
513e99ce780STzuyi Chang 
514e99ce780STzuyi Chang 	ret = rtd_pinctrl_get_group_pins(pcdev, group, &pins, &num_pins);
515e99ce780STzuyi Chang 	if (ret) {
516e99ce780STzuyi Chang 		dev_err(pcdev->dev, "Getting pins for group %s failed\n", group_name);
517e99ce780STzuyi Chang 		return ret;
518e99ce780STzuyi Chang 	}
519e99ce780STzuyi Chang 
520e99ce780STzuyi Chang 	for (i = 0; i < num_pins; i++) {
521e99ce780STzuyi Chang 		ret = rtd_pin_config_set(pcdev, pins[i], configs, num_configs);
522e99ce780STzuyi Chang 		if (ret)
523e99ce780STzuyi Chang 			return ret;
524e99ce780STzuyi Chang 	}
525e99ce780STzuyi Chang 
526e99ce780STzuyi Chang 	return 0;
527e99ce780STzuyi Chang }
528e99ce780STzuyi Chang 
529e99ce780STzuyi Chang static const struct pinconf_ops rtd_pinconf_ops = {
530e99ce780STzuyi Chang 	.is_generic = true,
531e99ce780STzuyi Chang 	.pin_config_get = rtd_pin_config_get,
532e99ce780STzuyi Chang 	.pin_config_set = rtd_pin_config_set,
533e99ce780STzuyi Chang 	.pin_config_group_set = rtd_pin_config_group_set,
534e99ce780STzuyi Chang };
535e99ce780STzuyi Chang 
536e99ce780STzuyi Chang static const struct regmap_config rtd_pinctrl_regmap_config = {
537e99ce780STzuyi Chang 	.reg_bits = 32,
538e99ce780STzuyi Chang 	.val_bits = 32,
539e99ce780STzuyi Chang 	.reg_stride = 4,
540e99ce780STzuyi Chang 	.use_relaxed_mmio = true,
541e99ce780STzuyi Chang };
542e99ce780STzuyi Chang 
rtd_pinctrl_probe(struct platform_device * pdev,const struct rtd_pinctrl_desc * desc)543e99ce780STzuyi Chang int rtd_pinctrl_probe(struct platform_device *pdev, const struct rtd_pinctrl_desc *desc)
544e99ce780STzuyi Chang {
545e99ce780STzuyi Chang 	struct rtd_pinctrl *data;
5468c58f51fSDan Carpenter 	int ret;
547e99ce780STzuyi Chang 
548e99ce780STzuyi Chang 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
549e99ce780STzuyi Chang 	if (!data)
550e99ce780STzuyi Chang 		return -ENOMEM;
551e99ce780STzuyi Chang 
552e99ce780STzuyi Chang 	data->base = of_iomap(pdev->dev.of_node, 0);
5538c58f51fSDan Carpenter 	if (!data->base)
5548c58f51fSDan Carpenter 		return -ENOMEM;
555e99ce780STzuyi Chang 
556e99ce780STzuyi Chang 	data->dev = &pdev->dev;
557e99ce780STzuyi Chang 	data->info = desc;
558e99ce780STzuyi Chang 	data->desc.name = dev_name(&pdev->dev);
559e99ce780STzuyi Chang 	data->desc.pins = data->info->pins;
560e99ce780STzuyi Chang 	data->desc.npins = data->info->num_pins;
561e99ce780STzuyi Chang 	data->desc.pctlops = &rtd_pinctrl_ops;
562e99ce780STzuyi Chang 	data->desc.pmxops = &rtd_pinmux_ops;
563e99ce780STzuyi Chang 	data->desc.confops = &rtd_pinconf_ops;
564e99ce780STzuyi Chang 	data->desc.custom_params = rtd_custom_bindings;
565e99ce780STzuyi Chang 	data->desc.num_custom_params = ARRAY_SIZE(rtd_custom_bindings);
566e99ce780STzuyi Chang 	data->desc.owner = THIS_MODULE;
567e99ce780STzuyi Chang 	data->regmap_pinctrl = devm_regmap_init_mmio(data->dev, data->base,
568e99ce780STzuyi Chang 						     &rtd_pinctrl_regmap_config);
569e99ce780STzuyi Chang 
570e99ce780STzuyi Chang 	if (IS_ERR(data->regmap_pinctrl)) {
571e99ce780STzuyi Chang 		dev_err(data->dev, "failed to init regmap: %ld\n",
572e99ce780STzuyi Chang 			PTR_ERR(data->regmap_pinctrl));
5738c58f51fSDan Carpenter 		ret = PTR_ERR(data->regmap_pinctrl);
5748c58f51fSDan Carpenter 		goto unmap;
575e99ce780STzuyi Chang 	}
576e99ce780STzuyi Chang 
577e99ce780STzuyi Chang 	data->pcdev = pinctrl_register(&data->desc, &pdev->dev, data);
5788c58f51fSDan Carpenter 	if (IS_ERR(data->pcdev)) {
5798c58f51fSDan Carpenter 		ret = PTR_ERR(data->pcdev);
5808c58f51fSDan Carpenter 		goto unmap;
5818c58f51fSDan Carpenter 	}
582e99ce780STzuyi Chang 
583e99ce780STzuyi Chang 	platform_set_drvdata(pdev, data);
584e99ce780STzuyi Chang 
585e99ce780STzuyi Chang 	dev_dbg(&pdev->dev, "probed\n");
586e99ce780STzuyi Chang 
587e99ce780STzuyi Chang 	return 0;
5888c58f51fSDan Carpenter 
5898c58f51fSDan Carpenter unmap:
5908c58f51fSDan Carpenter 	iounmap(data->base);
5918c58f51fSDan Carpenter 	return ret;
592e99ce780STzuyi Chang }
593e99ce780STzuyi Chang EXPORT_SYMBOL(rtd_pinctrl_probe);
594e99ce780STzuyi Chang 
595e99ce780STzuyi Chang MODULE_DESCRIPTION("Realtek DHC SoC pinctrl driver");
596e99ce780STzuyi Chang MODULE_LICENSE("GPL v2");
597