2 * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
28 * MAX77620 PMIC driver
31 #include <sys/param.h>
32 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/malloc.h>
41 #include <machine/bus.h>
43 #include <dev/regulator/regulator.h>
44 #include <dev/fdt/fdt_pinctrl.h>
45 #include <dev/gpio/gpiobusvar.h>
46 #include <dev/iicbus/iiconf.h>
47 #include <dev/iicbus/iicbus.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
51 #include <dt-bindings/mfd/max77620.h>
54 #include "regdev_if.h"
58 static struct ofw_compat_data compat_data
[] = {
59 {"maxim,max77620", 1},
63 #define LOCK(_sc) sx_xlock(&(_sc)->lock)
64 #define UNLOCK(_sc) sx_xunlock(&(_sc)->lock)
65 #define LOCK_INIT(_sc) sx_init(&(_sc)->lock, "max77620")
66 #define LOCK_DESTROY(_sc) sx_destroy(&(_sc)->lock);
67 #define ASSERT_LOCKED(_sc) sx_assert(&(_sc)->lock, SA_XLOCKED);
68 #define ASSERT_UNLOCKED(_sc) sx_assert(&(_sc)->lock, SA_UNLOCKED);
70 #define MAX77620_DEVICE_ID 0x0C
73 * Raw register access function.
76 max77620_read(struct max77620_softc
*sc
, uint8_t reg
, uint8_t *val
)
80 struct iic_msg msgs
[2] = {
81 {0, IIC_M_WR
, 1, &addr
},
82 {0, IIC_M_RD
, 1, val
},
85 msgs
[0].slave
= sc
->bus_addr
;
86 msgs
[1].slave
= sc
->bus_addr
;
89 rv
= iicbus_transfer(sc
->dev
, msgs
, 2);
91 device_printf(sc
->dev
,
92 "Error when reading reg 0x%02X, rv: %d\n", reg
, rv
);
99 int max77620_read_buf(struct max77620_softc
*sc
, uint8_t reg
, uint8_t *buf
,
104 struct iic_msg msgs
[2] = {
105 {0, IIC_M_WR
, 1, &addr
},
106 {0, IIC_M_RD
, size
, buf
},
109 msgs
[0].slave
= sc
->bus_addr
;
110 msgs
[1].slave
= sc
->bus_addr
;
113 rv
= iicbus_transfer(sc
->dev
, msgs
, 2);
115 device_printf(sc
->dev
,
116 "Error when reading reg 0x%02X, rv: %d\n", reg
, rv
);
124 max77620_write(struct max77620_softc
*sc
, uint8_t reg
, uint8_t val
)
129 struct iic_msg msgs
[1] = {
130 {0, IIC_M_WR
, 2, data
},
133 msgs
[0].slave
= sc
->bus_addr
;
137 rv
= iicbus_transfer(sc
->dev
, msgs
, 1);
139 device_printf(sc
->dev
,
140 "Error when writing reg 0x%02X, rv: %d\n", reg
, rv
);
147 max77620_write_buf(struct max77620_softc
*sc
, uint8_t reg
, uint8_t *buf
,
152 struct iic_msg msgs
[2] = {
153 {0, IIC_M_WR
, 1, data
},
154 {0, IIC_M_WR
| IIC_M_NOSTART
, size
, buf
},
157 msgs
[0].slave
= sc
->bus_addr
;
158 msgs
[1].slave
= sc
->bus_addr
;
161 rv
= iicbus_transfer(sc
->dev
, msgs
, 2);
163 device_printf(sc
->dev
,
164 "Error when writing reg 0x%02X, rv: %d\n", reg
, rv
);
171 max77620_modify(struct max77620_softc
*sc
, uint8_t reg
, uint8_t clear
,
177 rv
= max77620_read(sc
, reg
, &val
);
184 rv
= max77620_write(sc
, reg
, val
);
192 max77620_parse_fps(struct max77620_softc
*sc
, int id
, phandle_t node
)
196 if (OF_getencprop(node
, "maxim,shutdown-fps-time-period-us", &val
,
198 val
= min(val
, MAX77620_FPS_PERIOD_MAX_US
);
199 val
= max(val
, MAX77620_FPS_PERIOD_MIN_US
);
200 sc
->shutdown_fps
[id
] = val
;
202 if (OF_getencprop(node
, "maxim,suspend-fps-time-period-us", &val
,
204 val
= min(val
, MAX77620_FPS_PERIOD_MAX_US
);
205 val
= max(val
, MAX77620_FPS_PERIOD_MIN_US
);
206 sc
->suspend_fps
[id
] = val
;
208 if (OF_getencprop(node
, "maxim,fps-event-source", &val
,
211 device_printf(sc
->dev
, "Invalid 'fps-event-source' "
215 sc
->event_source
[id
] = val
;
221 max77620_parse_fdt(struct max77620_softc
*sc
, phandle_t node
)
227 for (i
= 0; i
< MAX77620_FPS_COUNT
; i
++) {
228 sc
->shutdown_fps
[i
] = -1;
229 sc
->suspend_fps
[i
] = -1;
230 sc
->event_source
[i
] = -1;
233 fpsnode
= ofw_bus_find_child(node
, "fps");
235 for (i
= 0; i
< MAX77620_FPS_COUNT
; i
++) {
236 sprintf(fps_name
, "fps%d", i
);
237 node
= ofw_bus_find_child(node
, fps_name
);
240 rv
= max77620_parse_fps(sc
, i
, node
);
249 max77620_get_version(struct max77620_softc
*sc
)
255 /* Verify ID string (5 bytes ). */
256 for (i
= 0; i
<= 6; i
++) {
257 rv
= RD1(sc
, MAX77620_REG_CID0
+ i
, buf
+ i
);
259 device_printf(sc
->dev
, "Cannot read chip ID: %d\n", rv
);
264 device_printf(sc
->dev
,
265 " ID: [0x%02X, 0x%02X, 0x%02X, 0x%02X]\n",
266 buf
[0], buf
[1], buf
[2], buf
[3]);
268 device_printf(sc
->dev
, " MAX77620 version - OTP: 0x%02X, ES: 0x%02X\n",
275 max77620_encode_fps_period(struct max77620_softc
*sc
, int val
)
280 period
= MAX77620_FPS_PERIOD_MIN_US
;
281 for (i
= 0; i
< 7; i
++) {
290 max77620_init(struct max77620_softc
*sc
)
292 uint8_t mask
, val
, tmp
;
297 for (i
= 0; i
< MAX77620_FPS_COUNT
; i
++) {
298 if (sc
->shutdown_fps
[i
] != -1) {
299 mask
|= MAX77620_FPS_TIME_PERIOD_MASK
;
300 tmp
= max77620_encode_fps_period(sc
,
301 sc
->shutdown_fps
[i
]);
302 val
|= (tmp
<< MAX77620_FPS_TIME_PERIOD_SHIFT
) &
303 MAX77620_FPS_TIME_PERIOD_MASK
;
306 if (sc
->event_source
[i
] != -1) {
307 mask
|= MAX77620_FPS_EN_SRC_MASK
;
308 tmp
= sc
->event_source
[i
];
309 val
|= (tmp
<< MAX77620_FPS_EN_SRC_SHIFT
) &
310 MAX77620_FPS_EN_SRC_MASK
;
311 if (sc
->event_source
[i
] == 2) {
312 mask
|= MAX77620_FPS_ENFPS_SW_MASK
;
313 val
|= MAX77620_FPS_ENFPS_SW
;
317 rv
= RM1(sc
, MAX77620_REG_FPS_CFG0
+ i
, mask
, val
);
319 device_printf(sc
->dev
, "I/O error: %d\n", rv
);
324 /* Global mask interrupts */
325 rv
= RM1(sc
, MAX77620_REG_INTENLBT
, 0x81, 0x81);
326 rv
= RM1(sc
, MAX77620_REG_IRQTOPM
, 0x81, 0x81);
333 max77620_intr(void *arg
)
335 struct max77620_softc
*sc
;
336 uint8_t intenlbt
, intlbt
, irqtop
, irqtopm
, irqsd
, irqmasksd
;
337 uint8_t irq_lvl2_l0_7
, irq_lvl2_l8
, irq_lvl2_gpio
, irq_msk_l0_7
, irq_msk_l8
;
338 uint8_t onoffirq
, onoffirqm
;
340 sc
= (struct max77620_softc
*)arg
;
341 /* XXX Finish temperature alarms. */
342 RD1(sc
, MAX77620_REG_INTENLBT
, &intenlbt
);
343 RD1(sc
, MAX77620_REG_INTLBT
, &intlbt
);
345 RD1(sc
, MAX77620_REG_IRQTOP
, &irqtop
);
346 RD1(sc
, MAX77620_REG_IRQTOPM
, &irqtopm
);
347 RD1(sc
, MAX77620_REG_IRQSD
, &irqsd
);
348 RD1(sc
, MAX77620_REG_IRQMASKSD
, &irqmasksd
);
349 RD1(sc
, MAX77620_REG_IRQ_LVL2_L0_7
, &irq_lvl2_l0_7
);
350 RD1(sc
, MAX77620_REG_IRQ_MSK_L0_7
, &irq_msk_l0_7
);
351 RD1(sc
, MAX77620_REG_IRQ_LVL2_L8
, &irq_lvl2_l8
);
352 RD1(sc
, MAX77620_REG_IRQ_MSK_L8
, &irq_msk_l8
);
353 RD1(sc
, MAX77620_REG_IRQ_LVL2_GPIO
, &irq_lvl2_gpio
);
354 RD1(sc
, MAX77620_REG_ONOFFIRQ
, &onoffirq
);
355 RD1(sc
, MAX77620_REG_ONOFFIRQM
, &onoffirqm
);
356 printf("%s: intlbt: 0x%02X, intenlbt: 0x%02X\n", __func__
, intlbt
, intenlbt
);
357 printf("%s: irqtop: 0x%02X, irqtopm: 0x%02X\n", __func__
, irqtop
, irqtopm
);
358 printf("%s: irqsd: 0x%02X, irqmasksd: 0x%02X\n", __func__
, irqsd
, irqmasksd
);
359 printf("%s: onoffirq: 0x%02X, onoffirqm: 0x%02X\n", __func__
, onoffirq
, onoffirqm
);
360 printf("%s: irq_lvl2_l0_7: 0x%02X, irq_msk_l0_7: 0x%02X\n", __func__
, irq_lvl2_l0_7
, irq_msk_l0_7
);
361 printf("%s: irq_lvl2_l8: 0x%02X, irq_msk_l8: 0x%02X\n", __func__
, irq_lvl2_l8
, irq_msk_l8
);
362 printf("%s: irq_lvl2_gpio: 0x%02X\n", __func__
, irq_lvl2_gpio
);
367 max77620_probe(device_t dev
)
370 if (!ofw_bus_status_okay(dev
))
373 if (!ofw_bus_search_compatible(dev
, compat_data
)->ocd_data
)
376 device_set_desc(dev
, "MAX77620 PMIC");
377 return (BUS_PROBE_DEFAULT
);
381 max77620_attach(device_t dev
)
383 struct max77620_softc
*sc
;
387 sc
= device_get_softc(dev
);
389 sc
->bus_addr
= iicbus_get_addr(dev
);
390 node
= ofw_bus_get_node(sc
->dev
);
395 sc
->irq_res
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
, &rid
,
397 #ifdef notyet /* Interrupt parent is not implemented */
398 if (sc
->irq_res
== NULL
) {
399 device_printf(dev
, "Cannot allocate interrupt.\n");
404 rv
= max77620_parse_fdt(sc
, node
);
408 rv
= max77620_get_version(sc
);
412 rv
= max77620_init(sc
);
415 rv
= max77620_regulator_attach(sc
, node
);
418 rv
= max77620_gpio_attach(sc
, node
);
422 rv
= max77620_rtc_create(sc
, node
);
426 fdt_pinctrl_register(dev
, NULL
);
427 fdt_pinctrl_configure_by_name(dev
, "default");
429 /* Setup interrupt. */
431 rv
= bus_setup_intr(dev
, sc
->irq_res
, INTR_TYPE_MISC
| INTR_MPSAFE
,
432 NULL
, max77620_intr
, sc
, &sc
->irq_h
);
434 device_printf(dev
, "Cannot setup interrupt.\n");
438 bus_attach_children(dev
);
442 if (sc
->irq_h
!= NULL
)
443 bus_teardown_intr(dev
, sc
->irq_res
, sc
->irq_h
);
444 if (sc
->irq_res
!= NULL
)
445 bus_release_resource(dev
, SYS_RES_IRQ
, 0, sc
->irq_res
);
451 max77620_detach(device_t dev
)
453 struct max77620_softc
*sc
;
456 error
= bus_generic_detach(dev
);
460 sc
= device_get_softc(dev
);
461 if (sc
->irq_h
!= NULL
)
462 bus_teardown_intr(dev
, sc
->irq_res
, sc
->irq_h
);
463 if (sc
->irq_res
!= NULL
)
464 bus_release_resource(dev
, SYS_RES_IRQ
, 0, sc
->irq_res
);
471 max77620_gpio_get_node(device_t bus
, device_t dev
)
474 /* We only have one child, the GPIO bus, which needs our own node. */
475 return (ofw_bus_get_node(bus
));
478 static device_method_t max77620_methods
[] = {
479 /* Device interface */
480 DEVMETHOD(device_probe
, max77620_probe
),
481 DEVMETHOD(device_attach
, max77620_attach
),
482 DEVMETHOD(device_detach
, max77620_detach
),
484 /* Regdev interface */
485 DEVMETHOD(regdev_map
, max77620_regulator_map
),
487 /* GPIO protocol interface */
488 DEVMETHOD(gpio_get_bus
, max77620_gpio_get_bus
),
489 DEVMETHOD(gpio_pin_max
, max77620_gpio_pin_max
),
490 DEVMETHOD(gpio_pin_getname
, max77620_gpio_pin_getname
),
491 DEVMETHOD(gpio_pin_getflags
, max77620_gpio_pin_getflags
),
492 DEVMETHOD(gpio_pin_getcaps
, max77620_gpio_pin_getcaps
),
493 DEVMETHOD(gpio_pin_setflags
, max77620_gpio_pin_setflags
),
494 DEVMETHOD(gpio_pin_get
, max77620_gpio_pin_get
),
495 DEVMETHOD(gpio_pin_set
, max77620_gpio_pin_set
),
496 DEVMETHOD(gpio_pin_toggle
, max77620_gpio_pin_toggle
),
497 DEVMETHOD(gpio_map_gpios
, max77620_gpio_map_gpios
),
499 /* fdt_pinctrl interface */
500 DEVMETHOD(fdt_pinctrl_configure
, max77620_pinmux_configure
),
502 /* ofw_bus interface */
503 DEVMETHOD(ofw_bus_get_node
, max77620_gpio_get_node
),
508 static DEFINE_CLASS_0(gpio
, max77620_driver
, max77620_methods
,
509 sizeof(struct max77620_softc
));
510 EARLY_DRIVER_MODULE(max77620
, iicbus
, max77620_driver
, NULL
, NULL
, 74);