2 * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
4 * SPDX-License-Identifier: GPL-2.0+
9 #include <dm/pinctrl.h>
10 #include <fdt_support.h>
11 #include <linux/err.h>
13 #include <linux/sizes.h>
15 #include "pinctrl-meson.h"
17 DECLARE_GLOBAL_DATA_PTR
;
19 static const char *meson_pinctrl_dummy_name
= "_dummy";
21 static int meson_pinctrl_get_groups_count(struct udevice
*dev
)
23 struct meson_pinctrl
*priv
= dev_get_priv(dev
);
25 return priv
->data
->num_groups
;
28 static const char *meson_pinctrl_get_group_name(struct udevice
*dev
,
31 struct meson_pinctrl
*priv
= dev_get_priv(dev
);
33 if (!priv
->data
->groups
[selector
].name
)
34 return meson_pinctrl_dummy_name
;
36 return priv
->data
->groups
[selector
].name
;
39 static int meson_pinmux_get_functions_count(struct udevice
*dev
)
41 struct meson_pinctrl
*priv
= dev_get_priv(dev
);
43 return priv
->data
->num_funcs
;
46 static const char *meson_pinmux_get_function_name(struct udevice
*dev
,
49 struct meson_pinctrl
*priv
= dev_get_priv(dev
);
51 return priv
->data
->funcs
[selector
].name
;
54 static void meson_pinmux_disable_other_groups(struct meson_pinctrl
*priv
,
55 unsigned int pin
, int sel_group
)
57 struct meson_pmx_group
*group
;
61 for (i
= 0; i
< priv
->data
->num_groups
; i
++) {
62 group
= &priv
->data
->groups
[i
];
63 if (group
->is_gpio
|| i
== sel_group
)
66 for (j
= 0; j
< group
->num_pins
; j
++) {
67 if (group
->pins
[j
] == pin
) {
68 /* We have found a group using the pin */
69 debug("pinmux: disabling %s\n", group
->name
);
70 addr
= priv
->reg_mux
+ group
->reg
* 4;
71 writel(readl(addr
) & ~BIT(group
->bit
), addr
);
77 static int meson_pinmux_group_set(struct udevice
*dev
,
78 unsigned group_selector
,
79 unsigned func_selector
)
81 struct meson_pinctrl
*priv
= dev_get_priv(dev
);
82 const struct meson_pmx_group
*group
;
83 const struct meson_pmx_func
*func
;
87 group
= &priv
->data
->groups
[group_selector
];
88 func
= &priv
->data
->funcs
[func_selector
];
90 debug("pinmux: set group %s func %s\n", group
->name
, func
->name
);
93 * Disable groups using the same pins.
94 * The selected group is not disabled to avoid glitches.
96 for (i
= 0; i
< group
->num_pins
; i
++) {
97 meson_pinmux_disable_other_groups(priv
,
102 /* Function 0 (GPIO) doesn't need any additional setting */
104 addr
= priv
->reg_mux
+ group
->reg
* 4;
105 writel(readl(addr
) | BIT(group
->bit
), addr
);
111 const struct pinctrl_ops meson_pinctrl_ops
= {
112 .get_groups_count
= meson_pinctrl_get_groups_count
,
113 .get_group_name
= meson_pinctrl_get_group_name
,
114 .get_functions_count
= meson_pinmux_get_functions_count
,
115 .get_function_name
= meson_pinmux_get_function_name
,
116 .pinmux_group_set
= meson_pinmux_group_set
,
117 .set_state
= pinctrl_generic_set_state
,
120 static fdt_addr_t
parse_address(int offset
, const char *name
, int na
, int ns
)
125 index
= fdt_stringlist_search(gd
->fdt_blob
, offset
, "reg-names", name
);
127 return FDT_ADDR_T_NONE
;
129 reg
= fdt_getprop(gd
->fdt_blob
, offset
, "reg", &len
);
130 if (!reg
|| (len
<= (index
* sizeof(fdt32_t
) * (na
+ ns
))))
131 return FDT_ADDR_T_NONE
;
133 reg
+= index
* (na
+ ns
);
135 return fdt_translate_address((void *)gd
->fdt_blob
, offset
, reg
);
138 int meson_pinctrl_probe(struct udevice
*dev
)
140 struct meson_pinctrl
*priv
= dev_get_priv(dev
);
142 int node
, gpio
= -1, len
;
145 na
= fdt_address_cells(gd
->fdt_blob
, dev
->parent
->of_offset
);
147 debug("bad #address-cells\n");
151 ns
= fdt_size_cells(gd
->fdt_blob
, dev
->parent
->of_offset
);
153 debug("bad #size-cells\n");
157 fdt_for_each_subnode(gd
->fdt_blob
, node
, dev
->of_offset
) {
158 if (fdt_getprop(gd
->fdt_blob
, node
, "gpio-controller", &len
)) {
165 debug("gpio node not found\n");
169 addr
= parse_address(gpio
, "mux", na
, ns
);
170 if (addr
== FDT_ADDR_T_NONE
) {
171 debug("mux not found\n");
175 priv
->reg_mux
= (void __iomem
*)addr
;
176 priv
->data
= (struct meson_pinctrl_data
*)dev_get_driver_data(dev
);