1e9034789SMichal Meloun /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3e9034789SMichal Meloun *
4e9034789SMichal Meloun * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5e9034789SMichal Meloun *
6e9034789SMichal Meloun * Redistribution and use in source and binary forms, with or without
7e9034789SMichal Meloun * modification, are permitted provided that the following conditions
8e9034789SMichal Meloun * are met:
9e9034789SMichal Meloun * 1. Redistributions of source code must retain the above copyright
10e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer.
11e9034789SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright
12e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer in the
13e9034789SMichal Meloun * documentation and/or other materials provided with the distribution.
14e9034789SMichal Meloun *
15e9034789SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e9034789SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e9034789SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e9034789SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e9034789SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e9034789SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e9034789SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e9034789SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e9034789SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e9034789SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e9034789SMichal Meloun * SUCH DAMAGE.
26e9034789SMichal Meloun */
27e9034789SMichal Meloun
28e9034789SMichal Meloun #include <sys/param.h>
29e9034789SMichal Meloun #include <sys/systm.h>
30e9034789SMichal Meloun #include <sys/bus.h>
31e9034789SMichal Meloun #include <sys/gpio.h>
32e9034789SMichal Meloun #include <sys/kernel.h>
33e9034789SMichal Meloun #include <sys/malloc.h>
34e9034789SMichal Meloun #include <sys/sx.h>
35e9034789SMichal Meloun
36e9034789SMichal Meloun #include <machine/bus.h>
37e9034789SMichal Meloun
38e9034789SMichal Meloun #include <dev/fdt/fdt_common.h>
39e9034789SMichal Meloun #include <dev/gpio/gpiobusvar.h>
40e9034789SMichal Meloun
41e9034789SMichal Meloun #include "max77620.h"
42e9034789SMichal Meloun
43e9034789SMichal Meloun MALLOC_DEFINE(M_MAX77620_GPIO, "MAX77620 gpio", "MAX77620 GPIO");
44e9034789SMichal Meloun
45e9034789SMichal Meloun #define NGPIO 8
46e9034789SMichal Meloun
47e9034789SMichal Meloun #define GPIO_LOCK(_sc) sx_slock(&(_sc)->gpio_lock)
48e9034789SMichal Meloun #define GPIO_UNLOCK(_sc) sx_unlock(&(_sc)->gpio_lock)
49e9034789SMichal Meloun #define GPIO_ASSERT(_sc) sx_assert(&(_sc)->gpio_lock, SA_LOCKED)
50e9034789SMichal Meloun
51e9034789SMichal Meloun enum prop_id {
52e9034789SMichal Meloun CFG_BIAS_PULL_UP,
53e9034789SMichal Meloun CFG_BIAS_PULL_DOWN,
54e9034789SMichal Meloun CFG_OPEN_DRAIN,
55e9034789SMichal Meloun CFG_PUSH_PULL,
56e9034789SMichal Meloun
57e9034789SMichal Meloun CFG_ACTIVE_FPS_SRC,
58e9034789SMichal Meloun CFG_ACTIVE_PWRUP_SLOT,
59e9034789SMichal Meloun CFG_ACTIVE_PWRDOWN_SLOT,
60e9034789SMichal Meloun CFG_SUSPEND_FPS_SRC,
61e9034789SMichal Meloun CFG_SUSPEND_PWRUP_SLOT,
62e9034789SMichal Meloun CFG_SUSPEND_PWRDOWN_SLOT,
63e9034789SMichal Meloun
64e9034789SMichal Meloun PROP_ID_MAX_ID
65e9034789SMichal Meloun };
66e9034789SMichal Meloun
67e9034789SMichal Meloun static const struct {
68e9034789SMichal Meloun const char *name;
69e9034789SMichal Meloun enum prop_id id;
70e9034789SMichal Meloun } max77620_prop_names[] = {
71e9034789SMichal Meloun {"bias-pull-up", CFG_BIAS_PULL_UP},
72e9034789SMichal Meloun {"bias-pull-down", CFG_BIAS_PULL_DOWN},
73e9034789SMichal Meloun {"drive-open-drain", CFG_OPEN_DRAIN},
74e9034789SMichal Meloun {"drive-push-pull", CFG_PUSH_PULL},
75e9034789SMichal Meloun {"maxim,active-fps-source", CFG_ACTIVE_FPS_SRC},
76e9034789SMichal Meloun {"maxim,active-fps-power-up-slot", CFG_ACTIVE_PWRUP_SLOT},
77e9034789SMichal Meloun {"maxim,active-fps-power-down-slot", CFG_ACTIVE_PWRDOWN_SLOT},
78e9034789SMichal Meloun {"maxim,suspend-fps-source", CFG_SUSPEND_FPS_SRC},
79e9034789SMichal Meloun {"maxim,suspend-fps-power-up-slot", CFG_SUSPEND_PWRUP_SLOT},
80e9034789SMichal Meloun {"maxim,suspend-fps-power-down-slot", CFG_SUSPEND_PWRDOWN_SLOT},
81e9034789SMichal Meloun };
82e9034789SMichal Meloun
83e9034789SMichal Meloun /* Configuration for one pin group. */
84e9034789SMichal Meloun struct max77620_pincfg {
85e9034789SMichal Meloun bool alt_func;
86e9034789SMichal Meloun int params[PROP_ID_MAX_ID];
87e9034789SMichal Meloun };
88e9034789SMichal Meloun
89e9034789SMichal Meloun static char *altfnc_table[] = {
90e9034789SMichal Meloun "lpm-control-in",
91e9034789SMichal Meloun "fps-out",
92e9034789SMichal Meloun "32k-out1",
93e9034789SMichal Meloun "sd0-dvs-in",
94e9034789SMichal Meloun "sd1-dvs-in",
95e9034789SMichal Meloun "reference-out",
96e9034789SMichal Meloun };
97e9034789SMichal Meloun
98e9034789SMichal Meloun struct max77620_gpio_pin {
99e9034789SMichal Meloun int pin_caps;
100e9034789SMichal Meloun char pin_name[GPIOMAXNAME];
101e9034789SMichal Meloun uint8_t reg;
102e9034789SMichal Meloun
103e9034789SMichal Meloun /* Runtime data */
104e9034789SMichal Meloun bool alt_func; /* GPIO or alternate function */
105e9034789SMichal Meloun };
106e9034789SMichal Meloun
107e9034789SMichal Meloun /* --------------------------------------------------------------------------
108e9034789SMichal Meloun *
109e9034789SMichal Meloun * Pinmux functions.
110e9034789SMichal Meloun */
111e9034789SMichal Meloun static int
max77620_pinmux_get_function(struct max77620_softc * sc,char * name,struct max77620_pincfg * cfg)112e9034789SMichal Meloun max77620_pinmux_get_function(struct max77620_softc *sc, char *name,
113e9034789SMichal Meloun struct max77620_pincfg *cfg)
114e9034789SMichal Meloun {
115e9034789SMichal Meloun int i;
116e9034789SMichal Meloun
117e9034789SMichal Meloun if (strcmp("gpio", name) == 0) {
118e9034789SMichal Meloun cfg->alt_func = false;
119e9034789SMichal Meloun return (0);
120e9034789SMichal Meloun }
121e9034789SMichal Meloun for (i = 0; i < nitems(altfnc_table); i++) {
122e9034789SMichal Meloun if (strcmp(altfnc_table[i], name) == 0) {
123e9034789SMichal Meloun cfg->alt_func = true;
124e9034789SMichal Meloun return (0);
125e9034789SMichal Meloun }
126e9034789SMichal Meloun }
127e9034789SMichal Meloun return (-1);
128e9034789SMichal Meloun }
129e9034789SMichal Meloun
130e9034789SMichal Meloun static int
max77620_pinmux_set_fps(struct max77620_softc * sc,int pin_num,struct max77620_gpio_pin * pin)131e9034789SMichal Meloun max77620_pinmux_set_fps(struct max77620_softc *sc, int pin_num,
132e9034789SMichal Meloun struct max77620_gpio_pin *pin)
133e9034789SMichal Meloun {
134e9034789SMichal Meloun #if 0
135e9034789SMichal Meloun struct max77620_fps_config *fps_config = &mpci->fps_config[pin];
136e9034789SMichal Meloun int addr, ret;
137e9034789SMichal Meloun int param_val;
138e9034789SMichal Meloun int mask, shift;
139e9034789SMichal Meloun
140e9034789SMichal Meloun if ((pin < 1) || (pin > 3))
141e9034789SMichal Meloun return (0);
142e9034789SMichal Meloun
143e9034789SMichal Meloun switch (param) {
144e9034789SMichal Meloun case MAX77620_ACTIVE_FPS_SOURCE:
145e9034789SMichal Meloun case MAX77620_SUSPEND_FPS_SOURCE:
146e9034789SMichal Meloun mask = MAX77620_FPS_SRC_MASK;
147e9034789SMichal Meloun shift = MAX77620_FPS_SRC_SHIFT;
148e9034789SMichal Meloun param_val = fps_config->active_fps_src;
149e9034789SMichal Meloun if (param == MAX77620_SUSPEND_FPS_SOURCE)
150e9034789SMichal Meloun param_val = fps_config->suspend_fps_src;
151e9034789SMichal Meloun break;
152e9034789SMichal Meloun
153e9034789SMichal Meloun case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:
154e9034789SMichal Meloun case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:
155e9034789SMichal Meloun mask = MAX77620_FPS_PU_PERIOD_MASK;
156e9034789SMichal Meloun shift = MAX77620_FPS_PU_PERIOD_SHIFT;
157e9034789SMichal Meloun param_val = fps_config->active_power_up_slots;
158e9034789SMichal Meloun if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)
159e9034789SMichal Meloun param_val = fps_config->suspend_power_up_slots;
160e9034789SMichal Meloun break;
161e9034789SMichal Meloun
162e9034789SMichal Meloun case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS:
163e9034789SMichal Meloun case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS:
164e9034789SMichal Meloun mask = MAX77620_FPS_PD_PERIOD_MASK;
165e9034789SMichal Meloun shift = MAX77620_FPS_PD_PERIOD_SHIFT;
166e9034789SMichal Meloun param_val = fps_config->active_power_down_slots;
167e9034789SMichal Meloun if (param == MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS)
168e9034789SMichal Meloun param_val = fps_config->suspend_power_down_slots;
169e9034789SMichal Meloun break;
170e9034789SMichal Meloun
171e9034789SMichal Meloun default:
172e9034789SMichal Meloun dev_err(mpci->dev, "Invalid parameter %d for pin %d\n",
173e9034789SMichal Meloun param, pin);
174e9034789SMichal Meloun return -EINVAL;
175e9034789SMichal Meloun }
176e9034789SMichal Meloun
177e9034789SMichal Meloun if (param_val < 0)
178e9034789SMichal Meloun return 0;
179e9034789SMichal Meloun
180e9034789SMichal Meloun ret = regmap_update_bits(mpci->rmap, addr, mask, param_val << shift);
181e9034789SMichal Meloun if (ret < 0)
182e9034789SMichal Meloun dev_err(mpci->dev, "Reg 0x%02x update failed %d\n", addr, ret);
183e9034789SMichal Meloun
184e9034789SMichal Meloun return ret;
185e9034789SMichal Meloun #endif
186e9034789SMichal Meloun return (0);
187e9034789SMichal Meloun }
188e9034789SMichal Meloun
189e9034789SMichal Meloun static int
max77620_pinmux_config_node(struct max77620_softc * sc,char * pin_name,struct max77620_pincfg * cfg)190e9034789SMichal Meloun max77620_pinmux_config_node(struct max77620_softc *sc, char *pin_name,
191e9034789SMichal Meloun struct max77620_pincfg *cfg)
192e9034789SMichal Meloun {
193e9034789SMichal Meloun struct max77620_gpio_pin *pin;
194e9034789SMichal Meloun uint8_t reg;
195e9034789SMichal Meloun int pin_num, rv;
196e9034789SMichal Meloun
197e9034789SMichal Meloun for (pin_num = 0; pin_num < sc->gpio_npins; pin_num++) {
198e9034789SMichal Meloun if (strcmp(sc->gpio_pins[pin_num]->pin_name, pin_name) == 0)
199e9034789SMichal Meloun break;
200e9034789SMichal Meloun }
201e9034789SMichal Meloun if (pin_num >= sc->gpio_npins) {
202e9034789SMichal Meloun device_printf(sc->dev, "Unknown pin: %s\n", pin_name);
203e9034789SMichal Meloun return (ENXIO);
204e9034789SMichal Meloun }
205e9034789SMichal Meloun pin = sc->gpio_pins[pin_num];
206e9034789SMichal Meloun
207e9034789SMichal Meloun rv = max77620_pinmux_set_fps(sc, pin_num, pin);
208e9034789SMichal Meloun if (rv != 0)
209e9034789SMichal Meloun return (rv);
210e9034789SMichal Meloun
211e9034789SMichal Meloun rv = RD1(sc, pin->reg, ®);
212e9034789SMichal Meloun if (rv != 0) {
213e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n");
214e9034789SMichal Meloun return (ENXIO);
215e9034789SMichal Meloun }
216e9034789SMichal Meloun
217e9034789SMichal Meloun if (cfg->alt_func) {
218e9034789SMichal Meloun pin->alt_func = true;
219e9034789SMichal Meloun sc->gpio_reg_ame |= 1 << pin_num;
220e9034789SMichal Meloun } else {
221e9034789SMichal Meloun pin->alt_func = false;
222e9034789SMichal Meloun sc->gpio_reg_ame &= ~(1 << pin_num);
223e9034789SMichal Meloun }
224e9034789SMichal Meloun
225e9034789SMichal Meloun /* Pull up/down. */
226e9034789SMichal Meloun switch (cfg->params[CFG_BIAS_PULL_UP]) {
227e9034789SMichal Meloun case 1:
228e9034789SMichal Meloun sc->gpio_reg_pue |= 1 << pin_num;
229e9034789SMichal Meloun break;
230e9034789SMichal Meloun case 0:
231e9034789SMichal Meloun sc->gpio_reg_pue &= ~(1 << pin_num);
232e9034789SMichal Meloun break;
233e9034789SMichal Meloun default:
234e9034789SMichal Meloun break;
235e9034789SMichal Meloun }
236e9034789SMichal Meloun
237e9034789SMichal Meloun switch (cfg->params[CFG_BIAS_PULL_DOWN]) {
238e9034789SMichal Meloun case 1:
239e9034789SMichal Meloun sc->gpio_reg_pde |= 1 << pin_num;
240e9034789SMichal Meloun break;
241e9034789SMichal Meloun case 0:
242e9034789SMichal Meloun sc->gpio_reg_pde &= ~(1 << pin_num);
243e9034789SMichal Meloun break;
244e9034789SMichal Meloun default:
245e9034789SMichal Meloun break;
246e9034789SMichal Meloun }
247e9034789SMichal Meloun
248e9034789SMichal Meloun /* Open drain/push-pull modes. */
249e9034789SMichal Meloun if (cfg->params[CFG_OPEN_DRAIN] == 1) {
250e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0);
251e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN);
252e9034789SMichal Meloun }
253e9034789SMichal Meloun
254e9034789SMichal Meloun if (cfg->params[CFG_PUSH_PULL] == 1) {
255e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0);
256e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_PUSHPULL);
257e9034789SMichal Meloun }
258e9034789SMichal Meloun
259e9034789SMichal Meloun rv = WR1(sc, pin->reg, reg);
260e9034789SMichal Meloun if (rv != 0) {
261e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n");
262e9034789SMichal Meloun return (ENXIO);
263e9034789SMichal Meloun }
264e9034789SMichal Meloun
265e9034789SMichal Meloun return (0);
266e9034789SMichal Meloun }
267e9034789SMichal Meloun
268e9034789SMichal Meloun static int
max77620_pinmux_read_node(struct max77620_softc * sc,phandle_t node,struct max77620_pincfg * cfg,char ** pins,int * lpins)269e9034789SMichal Meloun max77620_pinmux_read_node(struct max77620_softc *sc, phandle_t node,
270e9034789SMichal Meloun struct max77620_pincfg *cfg, char **pins, int *lpins)
271e9034789SMichal Meloun {
272e9034789SMichal Meloun char *function;
273e9034789SMichal Meloun int rv, i;
274e9034789SMichal Meloun
275e9034789SMichal Meloun *lpins = OF_getprop_alloc(node, "pins", (void **)pins);
276e9034789SMichal Meloun if (*lpins <= 0)
277e9034789SMichal Meloun return (ENOENT);
278e9034789SMichal Meloun
279e9034789SMichal Meloun /* Read function (mux) settings. */
280e9034789SMichal Meloun rv = OF_getprop_alloc(node, "function", (void **)&function);
281e9034789SMichal Meloun if (rv > 0) {
282e9034789SMichal Meloun rv = max77620_pinmux_get_function(sc, function, cfg);
283e9034789SMichal Meloun if (rv == -1) {
284e9034789SMichal Meloun device_printf(sc->dev,
285e9034789SMichal Meloun "Unknown function %s\n", function);
286e9034789SMichal Meloun OF_prop_free(function);
287e9034789SMichal Meloun return (ENXIO);
288e9034789SMichal Meloun }
289e9034789SMichal Meloun }
290e9034789SMichal Meloun
291e9034789SMichal Meloun /* Read numeric properties. */
292e9034789SMichal Meloun for (i = 0; i < PROP_ID_MAX_ID; i++) {
293e9034789SMichal Meloun rv = OF_getencprop(node, max77620_prop_names[i].name,
294e9034789SMichal Meloun &cfg->params[i], sizeof(cfg->params[i]));
295e9034789SMichal Meloun if (rv <= 0)
296e9034789SMichal Meloun cfg->params[i] = -1;
297e9034789SMichal Meloun }
298e9034789SMichal Meloun
299e9034789SMichal Meloun OF_prop_free(function);
300e9034789SMichal Meloun return (0);
301e9034789SMichal Meloun }
302e9034789SMichal Meloun
303e9034789SMichal Meloun static int
max77620_pinmux_process_node(struct max77620_softc * sc,phandle_t node)304e9034789SMichal Meloun max77620_pinmux_process_node(struct max77620_softc *sc, phandle_t node)
305e9034789SMichal Meloun {
306e9034789SMichal Meloun struct max77620_pincfg cfg;
307e9034789SMichal Meloun char *pins, *pname;
308e9034789SMichal Meloun int i, len, lpins, rv;
309e9034789SMichal Meloun
310e9034789SMichal Meloun rv = max77620_pinmux_read_node(sc, node, &cfg, &pins, &lpins);
311e9034789SMichal Meloun if (rv != 0)
312e9034789SMichal Meloun return (rv);
313e9034789SMichal Meloun
314e9034789SMichal Meloun len = 0;
315e9034789SMichal Meloun pname = pins;
316e9034789SMichal Meloun do {
317e9034789SMichal Meloun i = strlen(pname) + 1;
318e9034789SMichal Meloun rv = max77620_pinmux_config_node(sc, pname, &cfg);
319e9034789SMichal Meloun if (rv != 0) {
320e9034789SMichal Meloun device_printf(sc->dev,
321e9034789SMichal Meloun "Cannot configure pin: %s: %d\n", pname, rv);
322e9034789SMichal Meloun }
323e9034789SMichal Meloun len += i;
324e9034789SMichal Meloun pname += i;
325e9034789SMichal Meloun } while (len < lpins);
326e9034789SMichal Meloun
327e9034789SMichal Meloun if (pins != NULL)
328e9034789SMichal Meloun OF_prop_free(pins);
329e9034789SMichal Meloun
330e9034789SMichal Meloun return (rv);
331e9034789SMichal Meloun }
332e9034789SMichal Meloun
max77620_pinmux_configure(device_t dev,phandle_t cfgxref)333e9034789SMichal Meloun int max77620_pinmux_configure(device_t dev, phandle_t cfgxref)
334e9034789SMichal Meloun {
335e9034789SMichal Meloun struct max77620_softc *sc;
336e9034789SMichal Meloun phandle_t node, cfgnode;
337e9034789SMichal Meloun uint8_t old_reg_pue, old_reg_pde, old_reg_ame;
338e9034789SMichal Meloun int rv;
339e9034789SMichal Meloun
340e9034789SMichal Meloun sc = device_get_softc(dev);
341e9034789SMichal Meloun cfgnode = OF_node_from_xref(cfgxref);
342e9034789SMichal Meloun
343e9034789SMichal Meloun old_reg_pue = sc->gpio_reg_pue;
344e9034789SMichal Meloun old_reg_pde = sc->gpio_reg_pde;
345e9034789SMichal Meloun old_reg_ame = sc->gpio_reg_ame;
346e9034789SMichal Meloun
347e9034789SMichal Meloun for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
348e9034789SMichal Meloun if (!ofw_bus_node_status_okay(node))
349e9034789SMichal Meloun continue;
350e9034789SMichal Meloun rv = max77620_pinmux_process_node(sc, node);
351e9034789SMichal Meloun if (rv != 0)
352e9034789SMichal Meloun device_printf(dev, "Failed to process pinmux");
353e9034789SMichal Meloun
354e9034789SMichal Meloun }
355e9034789SMichal Meloun
356e9034789SMichal Meloun if (old_reg_pue != sc->gpio_reg_pue) {
357e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PUE_GPIO, sc->gpio_reg_pue);
358e9034789SMichal Meloun if (rv != 0) {
359e9034789SMichal Meloun device_printf(sc->dev,
360e9034789SMichal Meloun "Cannot update PUE_GPIO register\n");
361e9034789SMichal Meloun return (ENXIO);
362e9034789SMichal Meloun }
363e9034789SMichal Meloun }
364e9034789SMichal Meloun
365e9034789SMichal Meloun if (old_reg_pde != sc->gpio_reg_pde) {
366e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PDE_GPIO, sc->gpio_reg_pde);
367e9034789SMichal Meloun if (rv != 0) {
368e9034789SMichal Meloun device_printf(sc->dev,
369e9034789SMichal Meloun "Cannot update PDE_GPIO register\n");
370e9034789SMichal Meloun return (ENXIO);
371e9034789SMichal Meloun }
372e9034789SMichal Meloun }
373e9034789SMichal Meloun
374e9034789SMichal Meloun if (old_reg_ame != sc->gpio_reg_ame) {
375e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_AME_GPIO, sc->gpio_reg_ame);
376e9034789SMichal Meloun if (rv != 0) {
377e9034789SMichal Meloun device_printf(sc->dev,
378e9034789SMichal Meloun "Cannot update PDE_GPIO register\n");
379e9034789SMichal Meloun return (ENXIO);
380e9034789SMichal Meloun }
381e9034789SMichal Meloun }
382e9034789SMichal Meloun
383e9034789SMichal Meloun return (0);
384e9034789SMichal Meloun }
385e9034789SMichal Meloun
386e9034789SMichal Meloun /* --------------------------------------------------------------------------
387e9034789SMichal Meloun *
388e9034789SMichal Meloun * GPIO
389e9034789SMichal Meloun */
390e9034789SMichal Meloun device_t
max77620_gpio_get_bus(device_t dev)391e9034789SMichal Meloun max77620_gpio_get_bus(device_t dev)
392e9034789SMichal Meloun {
393e9034789SMichal Meloun struct max77620_softc *sc;
394e9034789SMichal Meloun
395e9034789SMichal Meloun sc = device_get_softc(dev);
396e9034789SMichal Meloun return (sc->gpio_busdev);
397e9034789SMichal Meloun }
398e9034789SMichal Meloun
399e9034789SMichal Meloun int
max77620_gpio_pin_max(device_t dev,int * maxpin)400e9034789SMichal Meloun max77620_gpio_pin_max(device_t dev, int *maxpin)
401e9034789SMichal Meloun {
402e9034789SMichal Meloun
403e9034789SMichal Meloun *maxpin = NGPIO - 1;
404e9034789SMichal Meloun return (0);
405e9034789SMichal Meloun }
406e9034789SMichal Meloun
407e9034789SMichal Meloun int
max77620_gpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)408e9034789SMichal Meloun max77620_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
409e9034789SMichal Meloun {
410e9034789SMichal Meloun struct max77620_softc *sc;
411e9034789SMichal Meloun
412e9034789SMichal Meloun sc = device_get_softc(dev);
413e9034789SMichal Meloun if (pin >= sc->gpio_npins)
414e9034789SMichal Meloun return (EINVAL);
415e9034789SMichal Meloun GPIO_LOCK(sc);
416e9034789SMichal Meloun *caps = sc->gpio_pins[pin]->pin_caps;
417e9034789SMichal Meloun GPIO_UNLOCK(sc);
418e9034789SMichal Meloun return (0);
419e9034789SMichal Meloun }
420e9034789SMichal Meloun
421e9034789SMichal Meloun int
max77620_gpio_pin_getname(device_t dev,uint32_t pin,char * name)422e9034789SMichal Meloun max77620_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
423e9034789SMichal Meloun {
424e9034789SMichal Meloun struct max77620_softc *sc;
425e9034789SMichal Meloun
426e9034789SMichal Meloun sc = device_get_softc(dev);
427e9034789SMichal Meloun if (pin >= sc->gpio_npins)
428e9034789SMichal Meloun return (EINVAL);
429e9034789SMichal Meloun GPIO_LOCK(sc);
430e9034789SMichal Meloun memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME);
431e9034789SMichal Meloun GPIO_UNLOCK(sc);
432e9034789SMichal Meloun return (0);
433e9034789SMichal Meloun }
434e9034789SMichal Meloun
435e9034789SMichal Meloun static int
max77620_gpio_get_mode(struct max77620_softc * sc,uint32_t pin_num,uint32_t * out_flags)436e9034789SMichal Meloun max77620_gpio_get_mode(struct max77620_softc *sc, uint32_t pin_num,
437e9034789SMichal Meloun uint32_t *out_flags)
438e9034789SMichal Meloun {
439e9034789SMichal Meloun struct max77620_gpio_pin *pin;
440e9034789SMichal Meloun uint8_t reg;
441e9034789SMichal Meloun int rv;
442e9034789SMichal Meloun
443e9034789SMichal Meloun pin = sc->gpio_pins[pin_num];
444e9034789SMichal Meloun *out_flags = 0;
445e9034789SMichal Meloun
446e9034789SMichal Meloun rv = RD1(sc, pin->reg, ®);
447e9034789SMichal Meloun if (rv != 0) {
448e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n");
449e9034789SMichal Meloun return (ENXIO);
450e9034789SMichal Meloun }
451e9034789SMichal Meloun
452e9034789SMichal Meloun /* Pin function */
453e9034789SMichal Meloun pin->alt_func = sc->gpio_reg_ame & (1 << pin_num);
454e9034789SMichal Meloun
455e9034789SMichal Meloun /* Pull up/down. */
456e9034789SMichal Meloun if (sc->gpio_reg_pue & (1 << pin_num))
457e9034789SMichal Meloun *out_flags |= GPIO_PIN_PULLUP;
458e9034789SMichal Meloun if (sc->gpio_reg_pde & (1 << pin_num))
459e9034789SMichal Meloun *out_flags |= GPIO_PIN_PULLDOWN;
460e9034789SMichal Meloun
461e9034789SMichal Meloun /* Open drain/push-pull modes. */
462e9034789SMichal Meloun if (MAX77620_REG_GPIO_DRV_GET(reg) == MAX77620_REG_GPIO_DRV_PUSHPULL)
463e9034789SMichal Meloun *out_flags |= GPIO_PIN_PUSHPULL;
464e9034789SMichal Meloun else
465e9034789SMichal Meloun *out_flags |= GPIO_PIN_OPENDRAIN;
466e9034789SMichal Meloun
467e9034789SMichal Meloun /* Input/output modes. */
468e9034789SMichal Meloun if (MAX77620_REG_GPIO_DRV_GET(reg) == MAX77620_REG_GPIO_DRV_PUSHPULL)
469e9034789SMichal Meloun *out_flags |= GPIO_PIN_OUTPUT;
470e9034789SMichal Meloun else
471e9034789SMichal Meloun *out_flags |= GPIO_PIN_OUTPUT | GPIO_PIN_INPUT;
472e9034789SMichal Meloun return (0);
473e9034789SMichal Meloun }
474e9034789SMichal Meloun
475e9034789SMichal Meloun int
max77620_gpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * out_flags)476e9034789SMichal Meloun max77620_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags)
477e9034789SMichal Meloun {
478e9034789SMichal Meloun struct max77620_softc *sc;
479e9034789SMichal Meloun int rv;
480e9034789SMichal Meloun
481e9034789SMichal Meloun sc = device_get_softc(dev);
482e9034789SMichal Meloun if (pin >= sc->gpio_npins)
483e9034789SMichal Meloun return (EINVAL);
484e9034789SMichal Meloun
485e9034789SMichal Meloun GPIO_LOCK(sc);
486e9034789SMichal Meloun #if 0 /* It colide with GPIO regulators */
487e9034789SMichal Meloun /* Is pin in GPIO mode ? */
488e9034789SMichal Meloun if (sc->gpio_pins[pin]->alt_func) {
489e9034789SMichal Meloun GPIO_UNLOCK(sc);
490e9034789SMichal Meloun return (ENXIO);
491e9034789SMichal Meloun }
492e9034789SMichal Meloun #endif
493e9034789SMichal Meloun rv = max77620_gpio_get_mode(sc, pin, out_flags);
494e9034789SMichal Meloun GPIO_UNLOCK(sc);
495e9034789SMichal Meloun
496e9034789SMichal Meloun return (rv);
497e9034789SMichal Meloun }
498e9034789SMichal Meloun
499e9034789SMichal Meloun int
max77620_gpio_pin_setflags(device_t dev,uint32_t pin_num,uint32_t flags)500e9034789SMichal Meloun max77620_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
501e9034789SMichal Meloun {
502e9034789SMichal Meloun struct max77620_softc *sc;
503e9034789SMichal Meloun struct max77620_gpio_pin *pin;
504e9034789SMichal Meloun uint8_t reg;
505e9034789SMichal Meloun uint8_t old_reg_pue, old_reg_pde;
506e9034789SMichal Meloun int rv;
507e9034789SMichal Meloun
508e9034789SMichal Meloun sc = device_get_softc(dev);
509e9034789SMichal Meloun if (pin_num >= sc->gpio_npins)
510e9034789SMichal Meloun return (EINVAL);
511e9034789SMichal Meloun
512e9034789SMichal Meloun pin = sc->gpio_pins[pin_num];
513e9034789SMichal Meloun
514e9034789SMichal Meloun GPIO_LOCK(sc);
515e9034789SMichal Meloun
516e9034789SMichal Meloun #if 0 /* It colide with GPIO regulators */
517e9034789SMichal Meloun /* Is pin in GPIO mode ? */
518e9034789SMichal Meloun if (pin->alt_func) {
519e9034789SMichal Meloun GPIO_UNLOCK(sc);
520e9034789SMichal Meloun return (ENXIO);
521e9034789SMichal Meloun }
522e9034789SMichal Meloun #endif
523e9034789SMichal Meloun
524e9034789SMichal Meloun old_reg_pue = sc->gpio_reg_pue;
525e9034789SMichal Meloun old_reg_pde = sc->gpio_reg_pde;
526e9034789SMichal Meloun
527e9034789SMichal Meloun rv = RD1(sc, pin->reg, ®);
528e9034789SMichal Meloun if (rv != 0) {
529e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n");
530e9034789SMichal Meloun GPIO_UNLOCK(sc);
531e9034789SMichal Meloun return (ENXIO);
532e9034789SMichal Meloun }
533e9034789SMichal Meloun
534e9034789SMichal Meloun if (flags & GPIO_PIN_PULLUP)
535e9034789SMichal Meloun sc->gpio_reg_pue |= 1 << pin_num;
536e9034789SMichal Meloun else
537e9034789SMichal Meloun sc->gpio_reg_pue &= ~(1 << pin_num);
538e9034789SMichal Meloun
539e9034789SMichal Meloun if (flags & GPIO_PIN_PULLDOWN)
540e9034789SMichal Meloun sc->gpio_reg_pde |= 1 << pin_num;
541e9034789SMichal Meloun else
542e9034789SMichal Meloun sc->gpio_reg_pde &= ~(1 << pin_num);
543e9034789SMichal Meloun
544e9034789SMichal Meloun if (flags & GPIO_PIN_INPUT) {
545e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0);
546e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN);
547e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_OUTPUT_VAL(~0);
548e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_OUTPUT_VAL(1);
549e9034789SMichal Meloun
550e9034789SMichal Meloun } else if (((flags & GPIO_PIN_OUTPUT) &&
551e9034789SMichal Meloun (flags & GPIO_PIN_OPENDRAIN) == 0) ||
552e9034789SMichal Meloun (flags & GPIO_PIN_PUSHPULL)) {
553e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0);
554e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_PUSHPULL);
555e9034789SMichal Meloun } else {
556e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0);
557e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN);
558e9034789SMichal Meloun }
559e9034789SMichal Meloun
560e9034789SMichal Meloun rv = WR1(sc, pin->reg, reg);
561e9034789SMichal Meloun if (rv != 0) {
562e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n");
563e9034789SMichal Meloun return (ENXIO);
564e9034789SMichal Meloun }
565e9034789SMichal Meloun if (old_reg_pue != sc->gpio_reg_pue) {
566e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PUE_GPIO, sc->gpio_reg_pue);
567e9034789SMichal Meloun if (rv != 0) {
568e9034789SMichal Meloun device_printf(sc->dev,
569e9034789SMichal Meloun "Cannot update PUE_GPIO register\n");
570e9034789SMichal Meloun GPIO_UNLOCK(sc);
571e9034789SMichal Meloun return (ENXIO);
572e9034789SMichal Meloun }
573e9034789SMichal Meloun }
574e9034789SMichal Meloun
575e9034789SMichal Meloun if (old_reg_pde != sc->gpio_reg_pde) {
576e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PDE_GPIO, sc->gpio_reg_pde);
577e9034789SMichal Meloun if (rv != 0) {
578e9034789SMichal Meloun device_printf(sc->dev,
579e9034789SMichal Meloun "Cannot update PDE_GPIO register\n");
580e9034789SMichal Meloun GPIO_UNLOCK(sc);
581e9034789SMichal Meloun return (ENXIO);
582e9034789SMichal Meloun }
583e9034789SMichal Meloun }
584e9034789SMichal Meloun
585e9034789SMichal Meloun GPIO_UNLOCK(sc);
586e9034789SMichal Meloun return (0);
587e9034789SMichal Meloun }
588e9034789SMichal Meloun
589e9034789SMichal Meloun int
max77620_gpio_pin_set(device_t dev,uint32_t pin,uint32_t val)590e9034789SMichal Meloun max77620_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val)
591e9034789SMichal Meloun {
592e9034789SMichal Meloun struct max77620_softc *sc;
593e9034789SMichal Meloun int rv;
594e9034789SMichal Meloun
595e9034789SMichal Meloun sc = device_get_softc(dev);
596e9034789SMichal Meloun if (pin >= sc->gpio_npins)
597e9034789SMichal Meloun return (EINVAL);
598e9034789SMichal Meloun
599e9034789SMichal Meloun GPIO_LOCK(sc);
600e9034789SMichal Meloun rv = RM1(sc, sc->gpio_pins[pin]->reg, MAX77620_REG_GPIO_OUTPUT_VAL(~0),
601e9034789SMichal Meloun MAX77620_REG_GPIO_OUTPUT_VAL(val));
602e9034789SMichal Meloun GPIO_UNLOCK(sc);
603e9034789SMichal Meloun return (rv);
604e9034789SMichal Meloun }
605e9034789SMichal Meloun
606e9034789SMichal Meloun int
max77620_gpio_pin_get(device_t dev,uint32_t pin,uint32_t * val)607e9034789SMichal Meloun max77620_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)
608e9034789SMichal Meloun {
609e9034789SMichal Meloun struct max77620_softc *sc;
610e9034789SMichal Meloun uint8_t tmp;
611e9034789SMichal Meloun int rv;
612e9034789SMichal Meloun
613e9034789SMichal Meloun sc = device_get_softc(dev);
614e9034789SMichal Meloun if (pin >= sc->gpio_npins)
615e9034789SMichal Meloun return (EINVAL);
616e9034789SMichal Meloun
617e9034789SMichal Meloun GPIO_LOCK(sc);
618e9034789SMichal Meloun rv = RD1(sc, sc->gpio_pins[pin]->reg, &tmp);
619e9034789SMichal Meloun
620e9034789SMichal Meloun if (MAX77620_REG_GPIO_DRV_GET(tmp) == MAX77620_REG_GPIO_DRV_PUSHPULL)
621e9034789SMichal Meloun *val = MAX77620_REG_GPIO_OUTPUT_VAL_GET(tmp);
622e9034789SMichal Meloun else
623e9034789SMichal Meloun *val = MAX77620_REG_GPIO_INPUT_VAL_GET(tmp);
624e9034789SMichal Meloun GPIO_UNLOCK(sc);
625e9034789SMichal Meloun if (rv != 0)
626e9034789SMichal Meloun return (rv);
627e9034789SMichal Meloun
628e9034789SMichal Meloun return (0);
629e9034789SMichal Meloun }
630e9034789SMichal Meloun
631e9034789SMichal Meloun int
max77620_gpio_pin_toggle(device_t dev,uint32_t pin)632e9034789SMichal Meloun max77620_gpio_pin_toggle(device_t dev, uint32_t pin)
633e9034789SMichal Meloun {
634e9034789SMichal Meloun struct max77620_softc *sc;
635e9034789SMichal Meloun uint8_t tmp;
636e9034789SMichal Meloun int rv;
637e9034789SMichal Meloun
638e9034789SMichal Meloun sc = device_get_softc(dev);
639e9034789SMichal Meloun if (pin >= sc->gpio_npins)
640e9034789SMichal Meloun return (EINVAL);
641e9034789SMichal Meloun
642e9034789SMichal Meloun GPIO_LOCK(sc);
643e9034789SMichal Meloun rv = RD1(sc, sc->gpio_pins[pin]->reg, &tmp);
644e9034789SMichal Meloun if (rv != 0) {
645e9034789SMichal Meloun GPIO_UNLOCK(sc);
646e9034789SMichal Meloun return (rv);
647e9034789SMichal Meloun }
648e9034789SMichal Meloun tmp ^= MAX77620_REG_GPIO_OUTPUT_VAL(~0);
649e9034789SMichal Meloun rv = RM1(sc, sc->gpio_pins[pin]->reg, MAX77620_REG_GPIO_OUTPUT_VAL(~0),
650e9034789SMichal Meloun tmp);
651e9034789SMichal Meloun GPIO_UNLOCK(sc);
652e9034789SMichal Meloun return (0);
653e9034789SMichal Meloun }
654e9034789SMichal Meloun
655e9034789SMichal Meloun int
max77620_gpio_map_gpios(device_t dev,phandle_t pdev,phandle_t gparent,int gcells,pcell_t * gpios,uint32_t * pin,uint32_t * flags)656e9034789SMichal Meloun max77620_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
657e9034789SMichal Meloun int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
658e9034789SMichal Meloun {
659e9034789SMichal Meloun
660e9034789SMichal Meloun if (gcells != 2)
661e9034789SMichal Meloun return (ERANGE);
662e9034789SMichal Meloun *pin = gpios[0];
663e9034789SMichal Meloun *flags= gpios[1];
664e9034789SMichal Meloun return (0);
665e9034789SMichal Meloun }
666e9034789SMichal Meloun
667e9034789SMichal Meloun int
max77620_gpio_attach(struct max77620_softc * sc,phandle_t node)668e9034789SMichal Meloun max77620_gpio_attach(struct max77620_softc *sc, phandle_t node)
669e9034789SMichal Meloun {
670e9034789SMichal Meloun struct max77620_gpio_pin *pin;
671e9034789SMichal Meloun int i, rv;
672e9034789SMichal Meloun
673e9034789SMichal Meloun sx_init(&sc->gpio_lock, "MAX77620 GPIO lock");
674e9034789SMichal Meloun
675e9034789SMichal Meloun sc->gpio_busdev = gpiobus_attach_bus(sc->dev);
676e9034789SMichal Meloun if (sc->gpio_busdev == NULL)
677e9034789SMichal Meloun return (ENXIO);
678e9034789SMichal Meloun
679e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_PUE_GPIO, &sc->gpio_reg_pue);
680e9034789SMichal Meloun if (rv != 0) {
681e9034789SMichal Meloun device_printf(sc->dev, "Cannot read PUE_GPIO register\n");
682e9034789SMichal Meloun return (ENXIO);
683e9034789SMichal Meloun }
684e9034789SMichal Meloun
685e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_PDE_GPIO, &sc->gpio_reg_pde);
686e9034789SMichal Meloun if (rv != 0) {
687e9034789SMichal Meloun device_printf(sc->dev, "Cannot read PDE_GPIO register\n");
688e9034789SMichal Meloun return (ENXIO);
689e9034789SMichal Meloun }
690e9034789SMichal Meloun
691e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_AME_GPIO, &sc->gpio_reg_ame);
692e9034789SMichal Meloun if (rv != 0) {
693e9034789SMichal Meloun device_printf(sc->dev, "Cannot read AME_GPIO register\n");
694e9034789SMichal Meloun return (ENXIO);
695e9034789SMichal Meloun }
696e9034789SMichal Meloun
697e9034789SMichal Meloun sc->gpio_npins = NGPIO;
698e9034789SMichal Meloun sc->gpio_pins = malloc(sizeof(struct max77620_gpio_pin *) *
699e9034789SMichal Meloun sc->gpio_npins, M_MAX77620_GPIO, M_WAITOK | M_ZERO);
700e9034789SMichal Meloun for (i = 0; i < sc->gpio_npins; i++) {
701e9034789SMichal Meloun sc->gpio_pins[i] = malloc(sizeof(struct max77620_gpio_pin),
702e9034789SMichal Meloun M_MAX77620_GPIO, M_WAITOK | M_ZERO);
703e9034789SMichal Meloun pin = sc->gpio_pins[i];
704e9034789SMichal Meloun sprintf(pin->pin_name, "gpio%d", i);
705e9034789SMichal Meloun pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
706e9034789SMichal Meloun GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL |
707e9034789SMichal Meloun GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
708e9034789SMichal Meloun pin->reg = MAX77620_REG_GPIO0 + i;
709e9034789SMichal Meloun }
710e9034789SMichal Meloun
711e9034789SMichal Meloun return (0);
712e9034789SMichal Meloun }
713