]>
Commit | Line | Data |
---|---|---|
caf2233b AG |
1 | /* |
2 | * Copyright (C) 2018 Alexander Graf <agraf@suse.de> | |
3 | * | |
4 | * Based on drivers/pinctrl/mvebu/pinctrl-mvebu.c and | |
5 | * drivers/gpio/bcm2835_gpio.c | |
6 | * | |
7 | * This driver gets instantiated by the GPIO driver, because both devices | |
8 | * share the same device node. | |
9 | * | |
10 | * SPDX-License-Identifier: GPL-2.0 | |
11 | * https://spdx.org/licenses | |
12 | */ | |
13 | ||
14 | #include <common.h> | |
15 | #include <config.h> | |
16 | #include <errno.h> | |
17 | #include <dm.h> | |
18 | #include <dm/pinctrl.h> | |
19 | #include <dm/root.h> | |
20 | #include <dm/device-internal.h> | |
21 | #include <dm/lists.h> | |
22 | #include <asm/system.h> | |
23 | #include <asm/io.h> | |
24 | #include <asm/gpio.h> | |
25 | ||
26 | struct bcm283x_pinctrl_priv { | |
27 | u32 *base_reg; | |
28 | }; | |
29 | ||
30 | #define MAX_PINS_PER_BANK 16 | |
31 | ||
32 | static void bcm2835_gpio_set_func_id(struct udevice *dev, unsigned int gpio, | |
33 | int func) | |
34 | { | |
35 | struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev); | |
36 | int reg_offset; | |
37 | int field_offset; | |
38 | ||
39 | reg_offset = BCM2835_GPIO_FSEL_BANK(gpio); | |
40 | field_offset = BCM2835_GPIO_FSEL_SHIFT(gpio); | |
41 | ||
42 | clrsetbits_le32(&priv->base_reg[reg_offset], | |
43 | BCM2835_GPIO_FSEL_MASK << field_offset, | |
44 | (func & BCM2835_GPIO_FSEL_MASK) << field_offset); | |
45 | } | |
46 | ||
47 | static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio) | |
48 | { | |
49 | struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev); | |
50 | u32 val; | |
51 | ||
52 | val = readl(&priv->base_reg[BCM2835_GPIO_FSEL_BANK(gpio)]); | |
53 | ||
54 | return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK); | |
55 | } | |
56 | ||
57 | /* | |
58 | * bcm283x_pinctrl_set_state: configure pin functions. | |
59 | * @dev: the pinctrl device to be configured. | |
60 | * @config: the state to be configured. | |
61 | * @return: 0 in success | |
62 | */ | |
63 | int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config) | |
64 | { | |
65 | u32 pin_arr[MAX_PINS_PER_BANK]; | |
66 | u32 function; | |
67 | int i, len, pin_count = 0; | |
68 | ||
69 | if (!dev_read_prop(config, "brcm,pins", &len) || !len || | |
70 | len & 0x3 || dev_read_u32_array(config, "brcm,pins", pin_arr, | |
71 | len / sizeof(u32))) { | |
72 | debug("Failed reading pins array for pinconfig %s (%d)\n", | |
73 | config->name, len); | |
74 | return -EINVAL; | |
75 | } | |
76 | ||
77 | pin_count = len / sizeof(u32); | |
78 | ||
79 | function = dev_read_u32_default(config, "brcm,function", -1); | |
80 | if (function < 0) { | |
81 | debug("Failed reading function for pinconfig %s (%d)\n", | |
82 | config->name, function); | |
83 | return -EINVAL; | |
84 | } | |
85 | ||
86 | for (i = 0; i < pin_count; i++) | |
87 | bcm2835_gpio_set_func_id(dev, pin_arr[i], function); | |
88 | ||
89 | return 0; | |
90 | } | |
91 | ||
92 | static int bcm283x_pinctrl_get_gpio_mux(struct udevice *dev, int banknum, | |
93 | int index) | |
94 | { | |
95 | if (banknum != 0) | |
96 | return -EINVAL; | |
97 | ||
98 | return bcm2835_gpio_get_func_id(dev, index); | |
99 | } | |
100 | ||
101 | static const struct udevice_id bcm2835_pinctrl_id[] = { | |
102 | {.compatible = "brcm,bcm2835-gpio"}, | |
103 | {} | |
104 | }; | |
105 | ||
106 | int bcm283x_pinctl_probe(struct udevice *dev) | |
107 | { | |
108 | struct bcm283x_pinctrl_priv *priv; | |
109 | int ret; | |
110 | struct udevice *pdev; | |
111 | ||
112 | priv = dev_get_priv(dev); | |
113 | if (!priv) { | |
114 | debug("%s: Failed to get private\n", __func__); | |
115 | return -EINVAL; | |
116 | } | |
117 | ||
118 | priv->base_reg = dev_read_addr_ptr(dev); | |
119 | if (priv->base_reg == (void *)FDT_ADDR_T_NONE) { | |
120 | debug("%s: Failed to get base address\n", __func__); | |
121 | return -EINVAL; | |
122 | } | |
123 | ||
124 | /* Create GPIO device as well */ | |
125 | ret = device_bind(dev, lists_driver_lookup_name("gpio_bcm2835"), | |
126 | "gpio_bcm2835", NULL, dev_of_offset(dev), &pdev); | |
127 | if (ret) { | |
128 | /* | |
129 | * While we really want the pinctrl driver to work to make | |
130 | * devices go where they should go, the GPIO controller is | |
131 | * not quite as crucial as it's only rarely used, so don't | |
132 | * fail here. | |
133 | */ | |
134 | printf("Failed to bind GPIO driver\n"); | |
135 | } | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
140 | static struct pinctrl_ops bcm283x_pinctrl_ops = { | |
141 | .set_state = bcm283x_pinctrl_set_state, | |
142 | .get_gpio_mux = bcm283x_pinctrl_get_gpio_mux, | |
143 | }; | |
144 | ||
145 | U_BOOT_DRIVER(pinctrl_bcm283x) = { | |
146 | .name = "bcm283x_pinctrl", | |
147 | .id = UCLASS_PINCTRL, | |
148 | .of_match = of_match_ptr(bcm2835_pinctrl_id), | |
149 | .priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv), | |
150 | .ops = &bcm283x_pinctrl_ops, | |
9821636b AG |
151 | .probe = bcm283x_pinctl_probe, |
152 | .flags = DM_FLAG_PRE_RELOC, | |
caf2233b | 153 | }; |