1/*-
2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28/*
29 * AS3722 PMIC driver
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/gpio.h>
36#include <sys/kernel.h>
37#include <sys/module.h>
38#include <sys/malloc.h>
39#include <sys/rman.h>
40#include <sys/sx.h>
41
42#include <machine/bus.h>
43
44#include <dev/regulator/regulator.h>
45#include <dev/fdt/fdt_pinctrl.h>
46#include <dev/gpio/gpiobusvar.h>
47#include <dev/iicbus/iiconf.h>
48#include <dev/iicbus/iicbus.h>
49#include <dev/ofw/ofw_bus.h>
50#include <dev/ofw/ofw_bus_subr.h>
51
52#include <dt-bindings/mfd/as3722.h>
53
54#include "clock_if.h"
55#include "regdev_if.h"
56
57#include "as3722.h"
58
59static struct ofw_compat_data compat_data[] = {
60	{"ams,as3722",		1},
61	{NULL,			0},
62};
63
64#define	LOCK(_sc)		sx_xlock(&(_sc)->lock)
65#define	UNLOCK(_sc)		sx_xunlock(&(_sc)->lock)
66#define	LOCK_INIT(_sc)		sx_init(&(_sc)->lock, "as3722")
67#define	LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->lock);
68#define	ASSERT_LOCKED(_sc)	sx_assert(&(_sc)->lock, SA_XLOCKED);
69#define	ASSERT_UNLOCKED(_sc)	sx_assert(&(_sc)->lock, SA_UNLOCKED);
70
71#define	AS3722_DEVICE_ID	0x0C
72
73/*
74 * Raw register access function.
75 */
76int
77as3722_read(struct as3722_softc *sc, uint8_t reg, uint8_t *val)
78{
79	uint8_t addr;
80	int rv;
81	struct iic_msg msgs[2] = {
82		{0, IIC_M_WR, 1, &addr},
83		{0, IIC_M_RD, 1, val},
84	};
85
86	msgs[0].slave = sc->bus_addr;
87	msgs[1].slave = sc->bus_addr;
88	addr = reg;
89
90	rv = iicbus_transfer(sc->dev, msgs, 2);
91	if (rv != 0) {
92		device_printf(sc->dev,
93		    "Error when reading reg 0x%02X, rv: %d\n", reg,  rv);
94		return (EIO);
95	}
96
97	return (0);
98}
99
100int as3722_read_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf,
101    size_t size)
102{
103	uint8_t addr;
104	int rv;
105	struct iic_msg msgs[2] = {
106		{0, IIC_M_WR, 1, &addr},
107		{0, IIC_M_RD, size, buf},
108	};
109
110	msgs[0].slave = sc->bus_addr;
111	msgs[1].slave = sc->bus_addr;
112	addr = reg;
113
114	rv = iicbus_transfer(sc->dev, msgs, 2);
115	if (rv != 0) {
116		device_printf(sc->dev,
117		    "Error when reading reg 0x%02X, rv: %d\n", reg,  rv);
118		return (EIO);
119	}
120
121	return (0);
122}
123
124int
125as3722_write(struct as3722_softc *sc, uint8_t reg, uint8_t val)
126{
127	uint8_t data[2];
128	int rv;
129
130	struct iic_msg msgs[1] = {
131		{0, IIC_M_WR, 2, data},
132	};
133
134	msgs[0].slave = sc->bus_addr;
135	data[0] = reg;
136	data[1] = val;
137
138	rv = iicbus_transfer(sc->dev, msgs, 1);
139	if (rv != 0) {
140		device_printf(sc->dev,
141		    "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
142		return (EIO);
143	}
144	return (0);
145}
146
147int as3722_write_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf,
148    size_t size)
149{
150	uint8_t data[1];
151	int rv;
152	struct iic_msg msgs[2] = {
153		{0, IIC_M_WR, 1, data},
154		{0, IIC_M_WR | IIC_M_NOSTART, size, buf},
155	};
156
157	msgs[0].slave = sc->bus_addr;
158	msgs[1].slave = sc->bus_addr;
159	data[0] = reg;
160
161	rv = iicbus_transfer(sc->dev, msgs, 2);
162	if (rv != 0) {
163		device_printf(sc->dev,
164		    "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
165		return (EIO);
166	}
167	return (0);
168}
169
170int
171as3722_modify(struct as3722_softc *sc, uint8_t reg, uint8_t clear, uint8_t set)
172{
173	uint8_t val;
174	int rv;
175
176	rv = as3722_read(sc, reg, &val);
177	if (rv != 0)
178		return (rv);
179
180	val &= ~clear;
181	val |= set;
182
183	rv = as3722_write(sc, reg, val);
184	if (rv != 0)
185		return (rv);
186
187	return (0);
188}
189
190static int
191as3722_get_version(struct as3722_softc *sc)
192{
193	uint8_t reg;
194	int rv;
195
196	/* Verify AS3722 ID and version. */
197	rv = RD1(sc, AS3722_ASIC_ID1, &reg);
198	if (rv != 0)
199		return (ENXIO);
200
201	if (reg != AS3722_DEVICE_ID) {
202		device_printf(sc->dev, "Invalid chip ID is 0x%x\n", reg);
203		return (ENXIO);
204	}
205
206	rv = RD1(sc, AS3722_ASIC_ID2, &sc->chip_rev);
207	if (rv != 0)
208		return (ENXIO);
209
210	if (bootverbose)
211		device_printf(sc->dev, "AS3722 rev: 0x%x\n", sc->chip_rev);
212	return (0);
213}
214
215static int
216as3722_init(struct as3722_softc *sc)
217{
218	uint32_t reg;
219	int rv;
220
221	reg = 0;
222	if (sc->int_pullup)
223		reg |= AS3722_INT_PULL_UP;
224	if (sc->i2c_pullup)
225		reg |= AS3722_I2C_PULL_UP;
226
227	rv = RM1(sc, AS3722_IO_VOLTAGE,
228	    AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, reg);
229	if (rv != 0)
230		return (ENXIO);
231
232	/* mask interrupts */
233	rv = WR1(sc, AS3722_INTERRUPT_MASK1, 0);
234	if (rv != 0)
235		return (ENXIO);
236	rv = WR1(sc, AS3722_INTERRUPT_MASK2, 0);
237	if (rv != 0)
238		return (ENXIO);
239	rv = WR1(sc, AS3722_INTERRUPT_MASK3, 0);
240	if (rv != 0)
241		return (ENXIO);
242	rv = WR1(sc, AS3722_INTERRUPT_MASK4, 0);
243	if (rv != 0)
244		return (ENXIO);
245	return (0);
246}
247
248static int
249as3722_parse_fdt(struct as3722_softc *sc, phandle_t node)
250{
251
252	sc->int_pullup =
253	    OF_hasprop(node, "ams,enable-internal-int-pullup") ? 1 : 0;
254	sc->i2c_pullup =
255	    OF_hasprop(node, "ams,enable-internal-i2c-pullup") ? 1 : 0;
256	return 0;
257}
258
259static void
260as3722_intr(void *arg)
261{
262	/* XXX Finish temperature alarms. */
263}
264
265static int
266as3722_probe(device_t dev)
267{
268
269	if (!ofw_bus_status_okay(dev))
270		return (ENXIO);
271
272	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
273		return (ENXIO);
274
275	device_set_desc(dev, "AS3722 PMIC");
276	return (BUS_PROBE_DEFAULT);
277}
278
279static int
280as3722_attach(device_t dev)
281{
282	struct as3722_softc *sc;
283	int rv, rid;
284	phandle_t node;
285
286	sc = device_get_softc(dev);
287	sc->dev = dev;
288	sc->bus_addr = iicbus_get_addr(dev);
289	node = ofw_bus_get_node(sc->dev);
290	rv = 0;
291	LOCK_INIT(sc);
292
293	rid = 0;
294	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
295	    RF_ACTIVE);
296	if (sc->irq_res == NULL) {
297		device_printf(dev, "Cannot allocate interrupt.\n");
298		rv = ENXIO;
299		goto fail;
300	}
301
302	rv = as3722_parse_fdt(sc, node);
303	if (rv != 0)
304		goto fail;
305	rv = as3722_get_version(sc);
306	if (rv != 0)
307		goto fail;
308	rv = as3722_init(sc);
309	if (rv != 0)
310		goto fail;
311	rv = as3722_regulator_attach(sc, node);
312	if (rv != 0)
313		goto fail;
314	rv = as3722_gpio_attach(sc, node);
315	if (rv != 0)
316		goto fail;
317	rv = as3722_rtc_attach(sc, node);
318	if (rv != 0)
319		goto fail;
320
321	fdt_pinctrl_register(dev, NULL);
322	fdt_pinctrl_configure_by_name(dev, "default");
323
324	/* Setup  interrupt. */
325	rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
326	    NULL, as3722_intr, sc, &sc->irq_h);
327	if (rv) {
328		device_printf(dev, "Cannot setup interrupt.\n");
329		goto fail;
330	}
331	return (bus_generic_attach(dev));
332
333fail:
334	if (sc->irq_h != NULL)
335		bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
336	if (sc->irq_res != NULL)
337		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
338	LOCK_DESTROY(sc);
339	return (rv);
340}
341
342static int
343as3722_detach(device_t dev)
344{
345	struct as3722_softc *sc;
346
347	sc = device_get_softc(dev);
348	if (sc->irq_h != NULL)
349		bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
350	if (sc->irq_res != NULL)
351		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
352	LOCK_DESTROY(sc);
353
354	return (bus_generic_detach(dev));
355}
356
357static phandle_t
358as3722_gpio_get_node(device_t bus, device_t dev)
359{
360
361	/* We only have one child, the GPIO bus, which needs our own node. */
362	return (ofw_bus_get_node(bus));
363}
364
365static device_method_t as3722_methods[] = {
366	/* Device interface */
367	DEVMETHOD(device_probe,		as3722_probe),
368	DEVMETHOD(device_attach,	as3722_attach),
369	DEVMETHOD(device_detach,	as3722_detach),
370
371	/* Regdev interface */
372	DEVMETHOD(regdev_map,		as3722_regulator_map),
373
374	/* RTC interface */
375	DEVMETHOD(clock_gettime,	as3722_rtc_gettime),
376	DEVMETHOD(clock_settime,	as3722_rtc_settime),
377
378	/* GPIO protocol interface */
379	DEVMETHOD(gpio_get_bus,		as3722_gpio_get_bus),
380	DEVMETHOD(gpio_pin_max,		as3722_gpio_pin_max),
381	DEVMETHOD(gpio_pin_getname,	as3722_gpio_pin_getname),
382	DEVMETHOD(gpio_pin_getflags,	as3722_gpio_pin_getflags),
383	DEVMETHOD(gpio_pin_getcaps,	as3722_gpio_pin_getcaps),
384	DEVMETHOD(gpio_pin_setflags,	as3722_gpio_pin_setflags),
385	DEVMETHOD(gpio_pin_get,		as3722_gpio_pin_get),
386	DEVMETHOD(gpio_pin_set,		as3722_gpio_pin_set),
387	DEVMETHOD(gpio_pin_toggle,	as3722_gpio_pin_toggle),
388	DEVMETHOD(gpio_map_gpios,	as3722_gpio_map_gpios),
389
390	/* fdt_pinctrl interface */
391	DEVMETHOD(fdt_pinctrl_configure, as3722_pinmux_configure),
392
393	/* ofw_bus interface */
394	DEVMETHOD(ofw_bus_get_node,	as3722_gpio_get_node),
395
396	DEVMETHOD_END
397};
398
399static DEFINE_CLASS_0(gpio, as3722_driver, as3722_methods,
400    sizeof(struct as3722_softc));
401EARLY_DRIVER_MODULE(as3722, iicbus, as3722_driver, NULL, NULL, 74);
402