1// SPDX-License-Identifier: GPL-2.0
2
3#include <common.h>
4#include <dm.h>
5#include <regmap.h>
6#include <syscon.h>
7#include <dm/device_compat.h>
8#include <dm/pinctrl.h>
9
10#define BCM6838_CMD_LOAD_MUX            0x21
11
12#define BCM6838_FUNC_OFFS               12
13#define BCM6838_FUNC_MASK               (0x37 << BCM6838_FUNC_OFFS)
14#define BCM6838_PIN_OFFS                 0
15#define BCM6838_PIN_MASK                (0xfff << BCM6838_PIN_OFFS)
16
17#define BCM6838_MAX_PIN_NAME_LEN         8
18static char bcm6838_pin_name[BCM6838_MAX_PIN_NAME_LEN];
19
20#define BCM6838_MAX_FUNC_NAME_LEN        8
21static char bcm6838_func_name[BCM6838_MAX_FUNC_NAME_LEN];
22
23struct bcm6838_test_port_hw {
24	unsigned long port_blk_data1;
25	unsigned long port_blk_data2;
26	unsigned long port_command;
27};
28
29static const struct bcm6838_test_port_hw bcm6838_hw = {
30	.port_blk_data1 = 0x10,
31	.port_blk_data2 = 0x14,
32	.port_command   = 0x18
33};
34
35struct bcm6838_pinctrl_priv {
36	const struct bcm6838_test_port_hw *hw;
37	struct regmap *regmap;
38	u32 pins_count;
39	u32 functions_count;
40};
41
42int bcm6838_pinctrl_get_pins_count(struct udevice *dev)
43{
44	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
45
46	return priv->pins_count;
47}
48
49const char *bcm6838_pinctrl_get_pin_name(struct udevice *dev,
50					 unsigned int selector)
51{
52	snprintf(bcm6838_pin_name, BCM6838_MAX_PIN_NAME_LEN, "%u", selector);
53	return bcm6838_pin_name;
54}
55
56int bcm6838_pinctrl_get_functions_count(struct udevice *dev)
57{
58	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
59
60	return priv->functions_count;
61}
62
63const char *bcm6838_pinctrl_get_function_name(struct udevice *dev,
64					      unsigned int selector)
65{
66	snprintf(bcm6838_func_name, BCM6838_MAX_FUNC_NAME_LEN, "%u", selector);
67	return bcm6838_func_name;
68}
69
70int bcm6838_pinctrl_pinmux_set(struct udevice *dev,
71			       unsigned int pin_selector,
72			       unsigned int func_selector)
73{
74	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
75	const struct bcm6838_test_port_hw *hw = priv->hw;
76	unsigned int data;
77
78	regmap_write(priv->regmap, hw->port_blk_data1, 0);
79	data = (func_selector << BCM6838_FUNC_OFFS) & BCM6838_FUNC_MASK;
80	data |= (pin_selector << BCM6838_PIN_OFFS) & BCM6838_PIN_MASK;
81	regmap_write(priv->regmap, hw->port_blk_data2, data);
82	regmap_write(priv->regmap, hw->port_command, BCM6838_CMD_LOAD_MUX);
83
84	return 0;
85}
86
87int bcm6838_pinctrl_probe(struct udevice *dev)
88{
89	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
90	const struct bcm6838_test_port_hw *hw =
91		(const struct bcm6838_test_port_hw *)dev_get_driver_data(dev);
92	int err;
93	u32 phandle;
94	ofnode node;
95
96	err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle);
97	if (err) {
98		dev_err(dev, "%s: unable to read regmap\n", __func__);
99		goto out;
100	}
101
102	node = ofnode_get_by_phandle(phandle);
103	if (!ofnode_valid(node)) {
104		dev_err(dev, "%s: unable to find node\n", __func__);
105		err = -EINVAL;
106		goto out;
107	}
108
109	priv->regmap = syscon_node_to_regmap(node);
110	if (!priv->regmap) {
111		dev_err(dev, "%s: unable to find regmap\n", __func__);
112		err = -ENODEV;
113		goto out;
114	}
115
116	err = ofnode_read_u32(dev_ofnode(dev), "brcm,pins-count",
117			      &priv->pins_count);
118	if (err) {
119		dev_err(dev, "%s: unable to read brcm,pins-count\n",
120			__func__);
121		goto out;
122	}
123
124	err = ofnode_read_u32(dev_ofnode(dev), "brcm,functions-count",
125			      &priv->functions_count);
126	if (err) {
127		dev_err(dev, "%s: unable to read brcm,functions-count\n",
128			__func__);
129		goto out;
130	}
131
132	priv->hw = hw;
133
134 out:
135	return err;
136}
137
138const struct pinctrl_ops bcm6838_pinctrl_ops = {
139	.set_state = pinctrl_generic_set_state,
140	.get_pins_count = bcm6838_pinctrl_get_pins_count,
141	.get_pin_name = bcm6838_pinctrl_get_pin_name,
142	.get_functions_count = bcm6838_pinctrl_get_functions_count,
143	.get_function_name = bcm6838_pinctrl_get_function_name,
144	.pinmux_set = bcm6838_pinctrl_pinmux_set,
145};
146
147static const struct udevice_id bcm6838_pinctrl_match[] = {
148	{
149		.compatible = "brcm,bcm6838-pinctrl",
150		.data = (ulong)&bcm6838_hw,
151	},
152	{ /* sentinel */ }
153};
154
155U_BOOT_DRIVER(bcm6838_pinctrl) = {
156	.name = "bcm6838_pinctrl",
157	.id = UCLASS_PINCTRL,
158	.of_match = bcm6838_pinctrl_match,
159	.ops = &bcm6838_pinctrl_ops,
160	.priv_auto	= sizeof(struct bcm6838_pinctrl_priv),
161	.probe = bcm6838_pinctrl_probe,
162};
163