1e9034789SMichal Meloun /*- 2e9034789SMichal Meloun * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> 3e9034789SMichal Meloun * 4e9034789SMichal Meloun * Redistribution and use in source and binary forms, with or without 5e9034789SMichal Meloun * modification, are permitted provided that the following conditions 6e9034789SMichal Meloun * are met: 7e9034789SMichal Meloun * 1. Redistributions of source code must retain the above copyright 8e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer. 9e9034789SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 10e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer in the 11e9034789SMichal Meloun * documentation and/or other materials provided with the distribution. 12e9034789SMichal Meloun * 13e9034789SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14e9034789SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15e9034789SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16e9034789SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17e9034789SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18e9034789SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19e9034789SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20e9034789SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21e9034789SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22e9034789SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23e9034789SMichal Meloun * SUCH DAMAGE. 24e9034789SMichal Meloun */ 25e9034789SMichal Meloun 26e9034789SMichal Meloun #include <sys/cdefs.h> 27e9034789SMichal Meloun __FBSDID("$FreeBSD$"); 28e9034789SMichal Meloun 29e9034789SMichal Meloun /* 30e9034789SMichal Meloun * MAX77620 PMIC driver 31e9034789SMichal Meloun */ 32e9034789SMichal Meloun 33e9034789SMichal Meloun #include <sys/param.h> 34e9034789SMichal Meloun #include <sys/systm.h> 35e9034789SMichal Meloun #include <sys/bus.h> 36e9034789SMichal Meloun #include <sys/gpio.h> 37e9034789SMichal Meloun #include <sys/kernel.h> 38e9034789SMichal Meloun #include <sys/module.h> 39e9034789SMichal Meloun #include <sys/malloc.h> 40e9034789SMichal Meloun #include <sys/rman.h> 41e9034789SMichal Meloun #include <sys/sx.h> 42e9034789SMichal Meloun 43e9034789SMichal Meloun #include <machine/bus.h> 44e9034789SMichal Meloun 45e9034789SMichal Meloun #include <dev/extres/regulator/regulator.h> 46e9034789SMichal Meloun #include <dev/fdt/fdt_pinctrl.h> 47e9034789SMichal Meloun #include <dev/gpio/gpiobusvar.h> 48e9034789SMichal Meloun #include <dev/iicbus/iiconf.h> 49e9034789SMichal Meloun #include <dev/iicbus/iicbus.h> 50e9034789SMichal Meloun #include <dev/ofw/ofw_bus.h> 51e9034789SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 52e9034789SMichal Meloun 53*c38fe878SEmmanuel Vadot #include <dt-bindings/mfd/max77620.h> 54e9034789SMichal Meloun 55e9034789SMichal Meloun #include "clock_if.h" 56e9034789SMichal Meloun #include "regdev_if.h" 57e9034789SMichal Meloun 58e9034789SMichal Meloun #include "max77620.h" 59e9034789SMichal Meloun 60e9034789SMichal Meloun static struct ofw_compat_data compat_data[] = { 61e9034789SMichal Meloun {"maxim,max77620", 1}, 62e9034789SMichal Meloun {NULL, 0}, 63e9034789SMichal Meloun }; 64e9034789SMichal Meloun 65e9034789SMichal Meloun #define LOCK(_sc) sx_xlock(&(_sc)->lock) 66e9034789SMichal Meloun #define UNLOCK(_sc) sx_xunlock(&(_sc)->lock) 67e9034789SMichal Meloun #define LOCK_INIT(_sc) sx_init(&(_sc)->lock, "max77620") 68e9034789SMichal Meloun #define LOCK_DESTROY(_sc) sx_destroy(&(_sc)->lock); 69e9034789SMichal Meloun #define ASSERT_LOCKED(_sc) sx_assert(&(_sc)->lock, SA_XLOCKED); 70e9034789SMichal Meloun #define ASSERT_UNLOCKED(_sc) sx_assert(&(_sc)->lock, SA_UNLOCKED); 71e9034789SMichal Meloun 72e9034789SMichal Meloun #define MAX77620_DEVICE_ID 0x0C 73e9034789SMichal Meloun 74e9034789SMichal Meloun /* 75e9034789SMichal Meloun * Raw register access function. 76e9034789SMichal Meloun */ 77e9034789SMichal Meloun int 78e9034789SMichal Meloun max77620_read(struct max77620_softc *sc, uint8_t reg, uint8_t *val) 79e9034789SMichal Meloun { 80e9034789SMichal Meloun uint8_t addr; 81e9034789SMichal Meloun int rv; 82e9034789SMichal Meloun struct iic_msg msgs[2] = { 83e9034789SMichal Meloun {0, IIC_M_WR, 1, &addr}, 84e9034789SMichal Meloun {0, IIC_M_RD, 1, val}, 85e9034789SMichal Meloun }; 86e9034789SMichal Meloun 87e9034789SMichal Meloun msgs[0].slave = sc->bus_addr; 88e9034789SMichal Meloun msgs[1].slave = sc->bus_addr; 89e9034789SMichal Meloun addr = reg; 90e9034789SMichal Meloun 91e9034789SMichal Meloun rv = iicbus_transfer(sc->dev, msgs, 2); 92e9034789SMichal Meloun if (rv != 0) { 93e9034789SMichal Meloun device_printf(sc->dev, 94e9034789SMichal Meloun "Error when reading reg 0x%02X, rv: %d\n", reg, rv); 95e9034789SMichal Meloun return (EIO); 96e9034789SMichal Meloun } 97e9034789SMichal Meloun 98e9034789SMichal Meloun return (0); 99e9034789SMichal Meloun } 100e9034789SMichal Meloun 101e9034789SMichal Meloun int max77620_read_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf, 102e9034789SMichal Meloun size_t size) 103e9034789SMichal Meloun { 104e9034789SMichal Meloun uint8_t addr; 105e9034789SMichal Meloun int rv; 106e9034789SMichal Meloun struct iic_msg msgs[2] = { 107e9034789SMichal Meloun {0, IIC_M_WR, 1, &addr}, 108e9034789SMichal Meloun {0, IIC_M_RD, size, buf}, 109e9034789SMichal Meloun }; 110e9034789SMichal Meloun 111e9034789SMichal Meloun msgs[0].slave = sc->bus_addr; 112e9034789SMichal Meloun msgs[1].slave = sc->bus_addr; 113e9034789SMichal Meloun addr = reg; 114e9034789SMichal Meloun 115e9034789SMichal Meloun rv = iicbus_transfer(sc->dev, msgs, 2); 116e9034789SMichal Meloun if (rv != 0) { 117e9034789SMichal Meloun device_printf(sc->dev, 118e9034789SMichal Meloun "Error when reading reg 0x%02X, rv: %d\n", reg, rv); 119e9034789SMichal Meloun return (EIO); 120e9034789SMichal Meloun } 121e9034789SMichal Meloun 122e9034789SMichal Meloun return (0); 123e9034789SMichal Meloun } 124e9034789SMichal Meloun 125e9034789SMichal Meloun int 126e9034789SMichal Meloun max77620_write(struct max77620_softc *sc, uint8_t reg, uint8_t val) 127e9034789SMichal Meloun { 128e9034789SMichal Meloun uint8_t data[2]; 129e9034789SMichal Meloun int rv; 130e9034789SMichal Meloun 131e9034789SMichal Meloun struct iic_msg msgs[1] = { 132e9034789SMichal Meloun {0, IIC_M_WR, 2, data}, 133e9034789SMichal Meloun }; 134e9034789SMichal Meloun 135e9034789SMichal Meloun msgs[0].slave = sc->bus_addr; 136e9034789SMichal Meloun data[0] = reg; 137e9034789SMichal Meloun data[1] = val; 138e9034789SMichal Meloun 139e9034789SMichal Meloun rv = iicbus_transfer(sc->dev, msgs, 1); 140e9034789SMichal Meloun if (rv != 0) { 141e9034789SMichal Meloun device_printf(sc->dev, 142e9034789SMichal Meloun "Error when writing reg 0x%02X, rv: %d\n", reg, rv); 143e9034789SMichal Meloun return (EIO); 144e9034789SMichal Meloun } 145e9034789SMichal Meloun return (0); 146e9034789SMichal Meloun } 147e9034789SMichal Meloun 148e9034789SMichal Meloun int 149e9034789SMichal Meloun max77620_write_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf, 150e9034789SMichal Meloun size_t size) 151e9034789SMichal Meloun { 152e9034789SMichal Meloun uint8_t data[1]; 153e9034789SMichal Meloun int rv; 154e9034789SMichal Meloun struct iic_msg msgs[2] = { 155e9034789SMichal Meloun {0, IIC_M_WR, 1, data}, 156e9034789SMichal Meloun {0, IIC_M_WR | IIC_M_NOSTART, size, buf}, 157e9034789SMichal Meloun }; 158e9034789SMichal Meloun 159e9034789SMichal Meloun msgs[0].slave = sc->bus_addr; 160e9034789SMichal Meloun msgs[1].slave = sc->bus_addr; 161e9034789SMichal Meloun data[0] = reg; 162e9034789SMichal Meloun 163e9034789SMichal Meloun rv = iicbus_transfer(sc->dev, msgs, 2); 164e9034789SMichal Meloun if (rv != 0) { 165e9034789SMichal Meloun device_printf(sc->dev, 166e9034789SMichal Meloun "Error when writing reg 0x%02X, rv: %d\n", reg, rv); 167e9034789SMichal Meloun return (EIO); 168e9034789SMichal Meloun } 169e9034789SMichal Meloun return (0); 170e9034789SMichal Meloun } 171e9034789SMichal Meloun 172e9034789SMichal Meloun int 173e9034789SMichal Meloun max77620_modify(struct max77620_softc *sc, uint8_t reg, uint8_t clear, 174e9034789SMichal Meloun uint8_t set) 175e9034789SMichal Meloun { 176e9034789SMichal Meloun uint8_t val; 177e9034789SMichal Meloun int rv; 178e9034789SMichal Meloun 179e9034789SMichal Meloun rv = max77620_read(sc, reg, &val); 180e9034789SMichal Meloun if (rv != 0) 181e9034789SMichal Meloun return (rv); 182e9034789SMichal Meloun 183e9034789SMichal Meloun val &= ~clear; 184e9034789SMichal Meloun val |= set; 185e9034789SMichal Meloun 186e9034789SMichal Meloun rv = max77620_write(sc, reg, val); 187e9034789SMichal Meloun if (rv != 0) 188e9034789SMichal Meloun return (rv); 189e9034789SMichal Meloun 190e9034789SMichal Meloun return (0); 191e9034789SMichal Meloun } 192e9034789SMichal Meloun 193e9034789SMichal Meloun static int 194e9034789SMichal Meloun max77620_parse_fps(struct max77620_softc *sc, int id, phandle_t node) 195e9034789SMichal Meloun { 196e9034789SMichal Meloun int val; 197e9034789SMichal Meloun 198e9034789SMichal Meloun if (OF_getencprop(node, "maxim,shutdown-fps-time-period-us", &val, 199e9034789SMichal Meloun sizeof(val)) >= 0) { 200e9034789SMichal Meloun val = min(val, MAX77620_FPS_PERIOD_MAX_US); 201e9034789SMichal Meloun val = max(val, MAX77620_FPS_PERIOD_MIN_US); 202e9034789SMichal Meloun sc->shutdown_fps[id] = val; 203e9034789SMichal Meloun } 204e9034789SMichal Meloun if (OF_getencprop(node, "maxim,suspend-fps-time-period-us", &val, 205e9034789SMichal Meloun sizeof(val)) >= 0) { 206e9034789SMichal Meloun val = min(val, MAX77620_FPS_PERIOD_MAX_US); 207e9034789SMichal Meloun val = max(val, MAX77620_FPS_PERIOD_MIN_US); 208e9034789SMichal Meloun sc->suspend_fps[id] = val; 209e9034789SMichal Meloun } 210e9034789SMichal Meloun if (OF_getencprop(node, "maxim,fps-event-source", &val, 211e9034789SMichal Meloun sizeof(val)) >= 0) { 212e9034789SMichal Meloun if (val > 2) { 213e9034789SMichal Meloun device_printf(sc->dev, "Invalid 'fps-event-source' " 214e9034789SMichal Meloun "value: %d\n", val); 215e9034789SMichal Meloun return (EINVAL); 216e9034789SMichal Meloun } 217e9034789SMichal Meloun sc->event_source[id] = val; 218e9034789SMichal Meloun } 219e9034789SMichal Meloun return (0); 220e9034789SMichal Meloun } 221e9034789SMichal Meloun 222e9034789SMichal Meloun static int 223e9034789SMichal Meloun max77620_parse_fdt(struct max77620_softc *sc, phandle_t node) 224e9034789SMichal Meloun { 225e9034789SMichal Meloun phandle_t fpsnode; 226e9034789SMichal Meloun char fps_name[6]; 227e9034789SMichal Meloun int i, rv; 228e9034789SMichal Meloun 229e9034789SMichal Meloun for (i = 0; i < MAX77620_FPS_COUNT; i++) { 230e9034789SMichal Meloun sc->shutdown_fps[i] = -1; 231e9034789SMichal Meloun sc->suspend_fps[i] = -1; 232e9034789SMichal Meloun sc->event_source[i] = -1; 233e9034789SMichal Meloun } 234e9034789SMichal Meloun 235e9034789SMichal Meloun fpsnode = ofw_bus_find_child(node, "fps"); 236e9034789SMichal Meloun if (fpsnode > 0) { 237e9034789SMichal Meloun for (i = 0; i < MAX77620_FPS_COUNT; i++) { 238e9034789SMichal Meloun sprintf(fps_name, "fps%d", i); 239e9034789SMichal Meloun node = ofw_bus_find_child(node, fps_name); 240e9034789SMichal Meloun if (node <= 0) 241e9034789SMichal Meloun continue; 242e9034789SMichal Meloun rv = max77620_parse_fps(sc, i, node); 243e9034789SMichal Meloun if (rv != 0) 244e9034789SMichal Meloun return (rv); 245e9034789SMichal Meloun } 246e9034789SMichal Meloun } 247e9034789SMichal Meloun return (0); 248e9034789SMichal Meloun } 249e9034789SMichal Meloun 250e9034789SMichal Meloun static int 251e9034789SMichal Meloun max77620_get_version(struct max77620_softc *sc) 252e9034789SMichal Meloun { 253e9034789SMichal Meloun uint8_t buf[6]; 254e9034789SMichal Meloun int i; 255e9034789SMichal Meloun int rv; 256e9034789SMichal Meloun 257e9034789SMichal Meloun /* Verify ID string (5 bytes ). */ 258e9034789SMichal Meloun for (i = 0; i <= 6; i++) { 259e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_CID0 + i , buf + i); 260e9034789SMichal Meloun if (rv != 0) { 261e9034789SMichal Meloun device_printf(sc->dev, "Cannot read chip ID: %d\n", rv); 262e9034789SMichal Meloun return (ENXIO); 263e9034789SMichal Meloun } 264e9034789SMichal Meloun } 265e9034789SMichal Meloun if (bootverbose) { 266e9034789SMichal Meloun device_printf(sc->dev, 267e9034789SMichal Meloun " ID: [0x%02X, 0x%02X, 0x%02X, 0x%02X]\n", 268e9034789SMichal Meloun buf[0], buf[1], buf[2], buf[3]); 269e9034789SMichal Meloun } 270e9034789SMichal Meloun device_printf(sc->dev, " MAX77620 version - OTP: 0x%02X, ES: 0x%02X\n", 271e9034789SMichal Meloun buf[4], buf[5]); 272e9034789SMichal Meloun 273e9034789SMichal Meloun return (0); 274e9034789SMichal Meloun } 275e9034789SMichal Meloun 276e9034789SMichal Meloun static uint8_t 277e9034789SMichal Meloun max77620_encode_fps_period(struct max77620_softc *sc, int val) 278e9034789SMichal Meloun { 279e9034789SMichal Meloun uint8_t i; 280e9034789SMichal Meloun int period; 281e9034789SMichal Meloun 282e9034789SMichal Meloun period = MAX77620_FPS_PERIOD_MIN_US; 283e9034789SMichal Meloun for (i = 0; i < 7; i++) { 284e9034789SMichal Meloun if (period >= val) 285e9034789SMichal Meloun return (i); 286e9034789SMichal Meloun period *= 2; 287e9034789SMichal Meloun } 288e9034789SMichal Meloun return (i); 289e9034789SMichal Meloun } 290e9034789SMichal Meloun 291e9034789SMichal Meloun static int 292e9034789SMichal Meloun max77620_init(struct max77620_softc *sc) 293e9034789SMichal Meloun { 294e9034789SMichal Meloun uint8_t mask, val, tmp;; 295e9034789SMichal Meloun int i, rv; 296e9034789SMichal Meloun 297e9034789SMichal Meloun mask = 0; 298e9034789SMichal Meloun val = 0; 299e9034789SMichal Meloun for (i = 0; i < MAX77620_FPS_COUNT; i++) { 300e9034789SMichal Meloun if (sc->shutdown_fps[i] != -1) { 301e9034789SMichal Meloun mask |= MAX77620_FPS_TIME_PERIOD_MASK; 302e9034789SMichal Meloun tmp = max77620_encode_fps_period(sc, 303e9034789SMichal Meloun sc->shutdown_fps[i]); 304e9034789SMichal Meloun val |= (tmp << MAX77620_FPS_TIME_PERIOD_SHIFT) & 305e9034789SMichal Meloun MAX77620_FPS_TIME_PERIOD_MASK; 306e9034789SMichal Meloun } 307e9034789SMichal Meloun 308e9034789SMichal Meloun if (sc->event_source[i] != -1) { 309e9034789SMichal Meloun mask |= MAX77620_FPS_EN_SRC_MASK; 310e9034789SMichal Meloun tmp = sc->event_source[i]; 311e9034789SMichal Meloun val |= (tmp << MAX77620_FPS_EN_SRC_SHIFT) & 312e9034789SMichal Meloun MAX77620_FPS_EN_SRC_MASK; 313e9034789SMichal Meloun if (sc->event_source[i] == 2) { 314e9034789SMichal Meloun mask |= MAX77620_FPS_ENFPS_SW_MASK; 315e9034789SMichal Meloun val |= MAX77620_FPS_ENFPS_SW; 316e9034789SMichal Meloun } 317e9034789SMichal Meloun 318e9034789SMichal Meloun } 319e9034789SMichal Meloun rv = RM1(sc, MAX77620_REG_FPS_CFG0 + i, mask, val); 320e9034789SMichal Meloun if (rv != 0) { 321e9034789SMichal Meloun device_printf(sc->dev, "I/O error: %d\n", rv); 322e9034789SMichal Meloun return (ENXIO); 323e9034789SMichal Meloun } 324e9034789SMichal Meloun } 325e9034789SMichal Meloun 326e9034789SMichal Meloun /* Global mask interrupts */ 327e9034789SMichal Meloun rv = RM1(sc, MAX77620_REG_INTENLBT, 0x81, 0x81); 328e9034789SMichal Meloun rv = RM1(sc, MAX77620_REG_IRQTOPM, 0x81, 0x81); 329e9034789SMichal Meloun if (rv != 0) 330e9034789SMichal Meloun return (ENXIO); 331e9034789SMichal Meloun return (0); 332e9034789SMichal Meloun } 333e9034789SMichal Meloun #ifdef notyet 334e9034789SMichal Meloun static void 335e9034789SMichal Meloun max77620_intr(void *arg) 336e9034789SMichal Meloun { 337e9034789SMichal Meloun struct max77620_softc *sc; 338e9034789SMichal Meloun uint8_t intenlbt, intlbt, irqtop, irqtopm, irqsd, irqmasksd; 339e9034789SMichal Meloun uint8_t irq_lvl2_l0_7, irq_lvl2_l8, irq_lvl2_gpio, irq_msk_l0_7, irq_msk_l8; 340e9034789SMichal Meloun uint8_t onoffirq, onoffirqm; 341e9034789SMichal Meloun 342e9034789SMichal Meloun sc = (struct max77620_softc *)arg; 343e9034789SMichal Meloun /* XXX Finish temperature alarms. */ 344e9034789SMichal Meloun RD1(sc, MAX77620_REG_INTENLBT, &intenlbt); 345e9034789SMichal Meloun RD1(sc, MAX77620_REG_INTLBT, &intlbt); 346e9034789SMichal Meloun 347e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQTOP, &irqtop); 348e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQTOPM, &irqtopm); 349e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQSD, &irqsd); 350e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQMASKSD, &irqmasksd); 351e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQ_LVL2_L0_7, &irq_lvl2_l0_7); 352e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQ_MSK_L0_7, &irq_msk_l0_7); 353e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQ_LVL2_L8, &irq_lvl2_l8); 354e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQ_MSK_L8, &irq_msk_l8); 355e9034789SMichal Meloun RD1(sc, MAX77620_REG_IRQ_LVL2_GPIO, &irq_lvl2_gpio); 356e9034789SMichal Meloun RD1(sc, MAX77620_REG_ONOFFIRQ, &onoffirq); 357e9034789SMichal Meloun RD1(sc, MAX77620_REG_ONOFFIRQM, &onoffirqm); 358e9034789SMichal Meloun printf("%s: intlbt: 0x%02X, intenlbt: 0x%02X\n", __func__, intlbt, intenlbt); 359e9034789SMichal Meloun printf("%s: irqtop: 0x%02X, irqtopm: 0x%02X\n", __func__, irqtop, irqtopm); 360e9034789SMichal Meloun printf("%s: irqsd: 0x%02X, irqmasksd: 0x%02X\n", __func__, irqsd, irqmasksd); 361e9034789SMichal Meloun printf("%s: onoffirq: 0x%02X, onoffirqm: 0x%02X\n", __func__, onoffirq, onoffirqm); 362e9034789SMichal Meloun printf("%s: irq_lvl2_l0_7: 0x%02X, irq_msk_l0_7: 0x%02X\n", __func__, irq_lvl2_l0_7, irq_msk_l0_7); 363e9034789SMichal Meloun printf("%s: irq_lvl2_l8: 0x%02X, irq_msk_l8: 0x%02X\n", __func__, irq_lvl2_l8, irq_msk_l8); 364e9034789SMichal Meloun printf("%s: irq_lvl2_gpio: 0x%02X\n", __func__, irq_lvl2_gpio); 365e9034789SMichal Meloun } 366e9034789SMichal Meloun #endif 367e9034789SMichal Meloun 368e9034789SMichal Meloun static int 369e9034789SMichal Meloun max77620_probe(device_t dev) 370e9034789SMichal Meloun { 371e9034789SMichal Meloun 372e9034789SMichal Meloun if (!ofw_bus_status_okay(dev)) 373e9034789SMichal Meloun return (ENXIO); 374e9034789SMichal Meloun 375e9034789SMichal Meloun if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 376e9034789SMichal Meloun return (ENXIO); 377e9034789SMichal Meloun 378e9034789SMichal Meloun device_set_desc(dev, "MAX77620 PMIC"); 379e9034789SMichal Meloun return (BUS_PROBE_DEFAULT); 380e9034789SMichal Meloun } 381e9034789SMichal Meloun 382e9034789SMichal Meloun static int 383e9034789SMichal Meloun max77620_attach(device_t dev) 384e9034789SMichal Meloun { 385e9034789SMichal Meloun struct max77620_softc *sc; 386e9034789SMichal Meloun const char *dname; 387e9034789SMichal Meloun int dunit, rv, rid; 388e9034789SMichal Meloun phandle_t node; 389e9034789SMichal Meloun 390e9034789SMichal Meloun sc = device_get_softc(dev); 391e9034789SMichal Meloun sc->dev = dev; 392e9034789SMichal Meloun sc->bus_addr = iicbus_get_addr(dev); 393e9034789SMichal Meloun node = ofw_bus_get_node(sc->dev); 394e9034789SMichal Meloun dname = device_get_name(dev); 395e9034789SMichal Meloun dunit = device_get_unit(dev); 396e9034789SMichal Meloun rv = 0; 397e9034789SMichal Meloun LOCK_INIT(sc); 398e9034789SMichal Meloun 399e9034789SMichal Meloun rid = 0; 400e9034789SMichal Meloun sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 401e9034789SMichal Meloun RF_ACTIVE); 40230ae4168SMichal Meloun #ifdef notyet /* Interrupt parent is not implemented */ 403e9034789SMichal Meloun if (sc->irq_res == NULL) { 404e9034789SMichal Meloun device_printf(dev, "Cannot allocate interrupt.\n"); 405e9034789SMichal Meloun rv = ENXIO; 406e9034789SMichal Meloun goto fail; 407e9034789SMichal Meloun } 408e9034789SMichal Meloun #endif 409e9034789SMichal Meloun rv = max77620_parse_fdt(sc, node); 410e9034789SMichal Meloun if (rv != 0) 411e9034789SMichal Meloun goto fail; 412e9034789SMichal Meloun 413e9034789SMichal Meloun rv = max77620_get_version(sc); 414e9034789SMichal Meloun if (rv != 0) 415e9034789SMichal Meloun goto fail; 416e9034789SMichal Meloun 417e9034789SMichal Meloun rv = max77620_init(sc); 418e9034789SMichal Meloun if (rv != 0) 419e9034789SMichal Meloun goto fail; 420e9034789SMichal Meloun rv = max77620_regulator_attach(sc, node); 421e9034789SMichal Meloun if (rv != 0) 422e9034789SMichal Meloun goto fail; 423e9034789SMichal Meloun rv = max77620_gpio_attach(sc, node); 424e9034789SMichal Meloun if (rv != 0) 425e9034789SMichal Meloun goto fail; 426e9034789SMichal Meloun 427e9034789SMichal Meloun rv = max77620_rtc_create(sc, node); 428e9034789SMichal Meloun if (rv != 0) 429e9034789SMichal Meloun goto fail; 430e9034789SMichal Meloun 431e9034789SMichal Meloun fdt_pinctrl_register(dev, NULL); 432e9034789SMichal Meloun fdt_pinctrl_configure_by_name(dev, "default"); 433e9034789SMichal Meloun 434e9034789SMichal Meloun /* Setup interrupt. */ 435e9034789SMichal Meloun #ifdef notyet 436e9034789SMichal Meloun rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 437e9034789SMichal Meloun NULL, max77620_intr, sc, &sc->irq_h); 438e9034789SMichal Meloun if (rv) { 439e9034789SMichal Meloun device_printf(dev, "Cannot setup interrupt.\n"); 440e9034789SMichal Meloun goto fail; 441e9034789SMichal Meloun } 442e9034789SMichal Meloun #endif 443e9034789SMichal Meloun return (bus_generic_attach(dev)); 444e9034789SMichal Meloun 445e9034789SMichal Meloun fail: 446e9034789SMichal Meloun if (sc->irq_h != NULL) 447e9034789SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 448e9034789SMichal Meloun if (sc->irq_res != NULL) 449e9034789SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 450e9034789SMichal Meloun LOCK_DESTROY(sc); 451e9034789SMichal Meloun return (rv); 452e9034789SMichal Meloun } 453e9034789SMichal Meloun 454e9034789SMichal Meloun static int 455e9034789SMichal Meloun max77620_detach(device_t dev) 456e9034789SMichal Meloun { 457e9034789SMichal Meloun struct max77620_softc *sc; 458e9034789SMichal Meloun 459e9034789SMichal Meloun sc = device_get_softc(dev); 460e9034789SMichal Meloun if (sc->irq_h != NULL) 461e9034789SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 462e9034789SMichal Meloun if (sc->irq_res != NULL) 463e9034789SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 464e9034789SMichal Meloun LOCK_DESTROY(sc); 465e9034789SMichal Meloun 466e9034789SMichal Meloun return (bus_generic_detach(dev)); 467e9034789SMichal Meloun } 468e9034789SMichal Meloun 469e9034789SMichal Meloun static phandle_t 470e9034789SMichal Meloun max77620_gpio_get_node(device_t bus, device_t dev) 471e9034789SMichal Meloun { 472e9034789SMichal Meloun 473e9034789SMichal Meloun /* We only have one child, the GPIO bus, which needs our own node. */ 474e9034789SMichal Meloun return (ofw_bus_get_node(bus)); 475e9034789SMichal Meloun } 476e9034789SMichal Meloun 477e9034789SMichal Meloun static device_method_t max77620_methods[] = { 478e9034789SMichal Meloun /* Device interface */ 479e9034789SMichal Meloun DEVMETHOD(device_probe, max77620_probe), 480e9034789SMichal Meloun DEVMETHOD(device_attach, max77620_attach), 481e9034789SMichal Meloun DEVMETHOD(device_detach, max77620_detach), 482e9034789SMichal Meloun 483e9034789SMichal Meloun /* Regdev interface */ 484e9034789SMichal Meloun DEVMETHOD(regdev_map, max77620_regulator_map), 485e9034789SMichal Meloun 486e9034789SMichal Meloun /* GPIO protocol interface */ 487e9034789SMichal Meloun DEVMETHOD(gpio_get_bus, max77620_gpio_get_bus), 488e9034789SMichal Meloun DEVMETHOD(gpio_pin_max, max77620_gpio_pin_max), 489e9034789SMichal Meloun DEVMETHOD(gpio_pin_getname, max77620_gpio_pin_getname), 490e9034789SMichal Meloun DEVMETHOD(gpio_pin_getflags, max77620_gpio_pin_getflags), 491e9034789SMichal Meloun DEVMETHOD(gpio_pin_getcaps, max77620_gpio_pin_getcaps), 492e9034789SMichal Meloun DEVMETHOD(gpio_pin_setflags, max77620_gpio_pin_setflags), 493e9034789SMichal Meloun DEVMETHOD(gpio_pin_get, max77620_gpio_pin_get), 494e9034789SMichal Meloun DEVMETHOD(gpio_pin_set, max77620_gpio_pin_set), 495e9034789SMichal Meloun DEVMETHOD(gpio_pin_toggle, max77620_gpio_pin_toggle), 496e9034789SMichal Meloun DEVMETHOD(gpio_map_gpios, max77620_gpio_map_gpios), 497e9034789SMichal Meloun 498e9034789SMichal Meloun /* fdt_pinctrl interface */ 499e9034789SMichal Meloun DEVMETHOD(fdt_pinctrl_configure, max77620_pinmux_configure), 500e9034789SMichal Meloun 501e9034789SMichal Meloun /* ofw_bus interface */ 502e9034789SMichal Meloun DEVMETHOD(ofw_bus_get_node, max77620_gpio_get_node), 503e9034789SMichal Meloun 504e9034789SMichal Meloun DEVMETHOD_END 505e9034789SMichal Meloun }; 506e9034789SMichal Meloun 507e9034789SMichal Meloun static devclass_t max77620_devclass; 508e9034789SMichal Meloun static DEFINE_CLASS_0(gpio, max77620_driver, max77620_methods, 509e9034789SMichal Meloun sizeof(struct max77620_softc)); 510e9034789SMichal Meloun EARLY_DRIVER_MODULE(max77620, iicbus, max77620_driver, max77620_devclass, 511e9034789SMichal Meloun NULL, NULL, 74); 512