1*32a67d49Skettenis /* $OpenBSD: rkpmic.c,v 1.18 2024/11/23 21:24:03 kettenis Exp $ */ 2ad688f68Skettenis /* 3ad688f68Skettenis * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> 4ad688f68Skettenis * 5ad688f68Skettenis * Permission to use, copy, modify, and distribute this software for any 6ad688f68Skettenis * purpose with or without fee is hereby granted, provided that the above 7ad688f68Skettenis * copyright notice and this permission notice appear in all copies. 8ad688f68Skettenis * 9ad688f68Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10ad688f68Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11ad688f68Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12ad688f68Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13ad688f68Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14ad688f68Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15ad688f68Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16ad688f68Skettenis */ 17ad688f68Skettenis 18ad688f68Skettenis #include <sys/param.h> 19ad688f68Skettenis #include <sys/systm.h> 20ad688f68Skettenis #include <sys/device.h> 2192bce581Skettenis #include <sys/malloc.h> 2230293cdcSkettenis #include <sys/proc.h> 2330293cdcSkettenis #include <sys/signalvar.h> 2430293cdcSkettenis 2530293cdcSkettenis #include <machine/fdt.h> 26ad688f68Skettenis 27ad688f68Skettenis #include <dev/ofw/openfirm.h> 2892bce581Skettenis #include <dev/ofw/ofw_regulator.h> 29ad688f68Skettenis #include <dev/ofw/fdt.h> 30ad688f68Skettenis 31ad688f68Skettenis #include <dev/i2c/i2cvar.h> 32ca857453Skettenis #include <dev/spi/spivar.h> 33ad688f68Skettenis 34ad688f68Skettenis #include <dev/clock_subr.h> 35ad688f68Skettenis 36*32a67d49Skettenis extern void (*powerdownfn)(void); 37*32a67d49Skettenis 38c23d9011Skurt #define RK80X_SECONDS 0x00 39c23d9011Skurt #define RK80X_MINUTES 0x01 40c23d9011Skurt #define RK80X_HOURS 0x02 41c23d9011Skurt #define RK80X_DAYS 0x03 42c23d9011Skurt #define RK80X_MONTHS 0x04 43c23d9011Skurt #define RK80X_YEARS 0x05 44c23d9011Skurt #define RK80X_WEEKS 0x06 45c23d9011Skurt #define RK80X_NRTC_REGS 7 46ad688f68Skettenis 47c23d9011Skurt #define RK805_RTC_CTRL 0x10 48c23d9011Skurt #define RK808_RTC_CTRL 0x10 49c23d9011Skurt #define RK809_RTC_CTRL 0x0d 50c23d9011Skurt #define RK80X_RTC_CTRL_STOP_RTC 0x01 51c23d9011Skurt 52c23d9011Skurt #define RK805_RTC_STATUS 0x11 53c23d9011Skurt #define RK808_RTC_STATUS 0x11 54c23d9011Skurt #define RK809_RTC_STATUS 0x0e 55c23d9011Skurt #define RK80X_RTC_STATUS_POWER_UP 0x80 56c23d9011Skurt 57*32a67d49Skettenis #define RK805_DEV_CTRL 0x4b 58*32a67d49Skettenis #define RK805_DEV_CTRL_DEV_OFF 0x01 59*32a67d49Skettenis 60*32a67d49Skettenis #define RK806_SYS_CFG3 0x72 61*32a67d49Skettenis #define RK806_SYS_CFG3_DEV_OFF 0x01 62*32a67d49Skettenis 63*32a67d49Skettenis #define RK808_DEVCTRL 0x4b 64*32a67d49Skettenis #define RK808_DEVCTRL_DEV_OFF_RST 0x08 65*32a67d49Skettenis 6630293cdcSkettenis #define RK809_PMIC_SYS_CFG3 0xf4 6730293cdcSkettenis #define RK809_PMIC_SYS_CFG3_SLP_FUN_MASK 0x18 6830293cdcSkettenis #define RK809_PMIC_SYS_CFG3_SLP_FUN_NONE 0x00 6930293cdcSkettenis #define RK809_PMIC_SYS_CFG3_SLP_FUN_SLEEP 0x08 70*32a67d49Skettenis #define RK809_PMIC_SYS_CFG3_DEV_OFF 0x01 7130293cdcSkettenis #define RK809_PMIC_INT_STS0 0xf8 7230293cdcSkettenis #define RK809_PMIC_INT_MSK0 0xf9 7330293cdcSkettenis #define RK809_PMIC_INT_MSK0_PWRON_FALL_INT_IM 0x01 7430293cdcSkettenis #define RK809_PMIC_INT_STS1 0xfa 7530293cdcSkettenis #define RK809_PMIC_INT_MSK1 0xfb 7630293cdcSkettenis #define RK809_PMIC_INT_STS2 0xfc 7730293cdcSkettenis #define RK809_PMIC_INT_MSK2 0xfd 7830293cdcSkettenis #define RK809_PMIC_GPIO_INT_CONFIG 0xfe 7930293cdcSkettenis #define RK809_PMIC_GPIO_INT_CONFIG_INT_POL 0x02 8030293cdcSkettenis 81ca857453Skettenis #define RKSPI_CMD_READ (0 << 7) 82ca857453Skettenis #define RKSPI_CMD_WRITE (1 << 7) 83ca857453Skettenis 84c23d9011Skurt struct rkpmic_vsel_range { 85c23d9011Skurt uint32_t base, delta; 86c23d9011Skurt uint8_t vsel_min, vsel_max; 87c23d9011Skurt }; 88ad688f68Skettenis 8992bce581Skettenis struct rkpmic_regdata { 9092bce581Skettenis const char *name; 91b8599033Skettenis uint8_t vreg, vmask; 92b8599033Skettenis uint8_t sreg, smask; 9337c734d3Snaddy const struct rkpmic_vsel_range *vsel_range; 94c23d9011Skurt }; 95c23d9011Skurt 96c23d9011Skurt /* 97c23d9011Skurt * Used by RK805 for BUCK1, BUCK2 98c23d9011Skurt * 0-59: 0.7125V-1.45V, step=12.5mV 99c23d9011Skurt * 60-62: 1.8V-2.2V, step=200mV 100c23d9011Skurt * 63: 2.3V 101c23d9011Skurt */ 10237c734d3Snaddy const struct rkpmic_vsel_range rk805_vsel_range1[] = { 103c23d9011Skurt { 712500, 12500, 0, 59 }, 104c23d9011Skurt { 1800000, 200000, 60, 62 }, 105c23d9011Skurt { 2300000, 0, 63, 63 }, 106c23d9011Skurt {} 107c23d9011Skurt }; 108c23d9011Skurt 109c23d9011Skurt /* 110c23d9011Skurt * Used by RK805 for BUCK4 111c23d9011Skurt * 0-27: 0.8V-3.5V, step=100mV 112c23d9011Skurt */ 11337c734d3Snaddy const struct rkpmic_vsel_range rk805_vsel_range2[] = { 114c23d9011Skurt { 800000, 100000, 0, 27 }, 115c23d9011Skurt {} 116c23d9011Skurt }; 117c23d9011Skurt 118c23d9011Skurt /* 119c23d9011Skurt * Used by RK805 for LDO1-3 120c23d9011Skurt * 0-26: 0.8V-3.4V, step=100mV 121c23d9011Skurt */ 12237c734d3Snaddy const struct rkpmic_vsel_range rk805_vsel_range3[] = { 123c23d9011Skurt { 800000, 100000, 0, 26 }, 124c23d9011Skurt {} 12592bce581Skettenis }; 12692bce581Skettenis 12737c734d3Snaddy const struct rkpmic_regdata rk805_regdata[] = { 128b8599033Skettenis { "DCDC_REG1", 0x2f, 0x3f, 0, 0, rk805_vsel_range1 }, 129b8599033Skettenis { "DCDC_REG2", 0x33, 0x3f, 0, 0, rk805_vsel_range1 }, 130b8599033Skettenis { "DCDC_REG4", 0x38, 0x1f, 0, 0, rk805_vsel_range2 }, 131b8599033Skettenis { "LDO_REG1", 0x3b, 0x1f, 0, 0, rk805_vsel_range3 }, 132b8599033Skettenis { "LDO_REG2", 0x3d, 0x1f, 0, 0, rk805_vsel_range3 }, 133b8599033Skettenis { "LDO_REG3", 0x3f, 0x1f, 0, 0, rk805_vsel_range3 }, 134c23d9011Skurt { } 135c23d9011Skurt }; 136c23d9011Skurt 137c23d9011Skurt /* 138ca857453Skettenis * Used by RK806 for BUCK 139ca857453Skettenis * 0-159: 0.5V-1.5V, step=6.25mV 140ca857453Skettenis * 160-236: 1.5V-3.4V, step=25mV 141ca857453Skettenis * 237-255: 3.4V-3.4V, step=0mV 142ca857453Skettenis */ 143ca857453Skettenis const struct rkpmic_vsel_range rk806_vsel_range1[] = { 144ca857453Skettenis { 500000, 6250, 0, 159 }, 145ca857453Skettenis { 1500000, 25000, 160, 236 }, 146ca857453Skettenis { 3400000, 0, 237, 255 }, 147ca857453Skettenis {} 148ca857453Skettenis }; 149ca857453Skettenis 150ca857453Skettenis /* 151ca857453Skettenis * Used by RK806 for LDO 152ca857453Skettenis * 0-232: 0.5V-3.4V, step=12.5mV 153ca857453Skettenis * 233-255: 3.4V-3.4V, step=0mV 154ca857453Skettenis */ 155ca857453Skettenis const struct rkpmic_vsel_range rk806_vsel_range2[] = { 156ca857453Skettenis { 500000, 12500, 0, 232 }, 157ca857453Skettenis { 3400000, 0, 233, 255 }, 158ca857453Skettenis {} 159ca857453Skettenis }; 160ca857453Skettenis 161ca857453Skettenis const struct rkpmic_regdata rk806_regdata[] = { 162b8599033Skettenis { "dcdc-reg1", 0x1a, 0xff, 0, 0, rk806_vsel_range1 }, 163b8599033Skettenis { "dcdc-reg2", 0x1b, 0xff, 0, 0, rk806_vsel_range1 }, 164b8599033Skettenis { "dcdc-reg3", 0x1c, 0xff, 0, 0, rk806_vsel_range1 }, 165b8599033Skettenis { "dcdc-reg4", 0x1d, 0xff, 0, 0, rk806_vsel_range1 }, 166b8599033Skettenis { "dcdc-reg5", 0x1e, 0xff, 0, 0, rk806_vsel_range1 }, 167b8599033Skettenis { "dcdc-reg6", 0x1f, 0xff, 0, 0, rk806_vsel_range1 }, 168b8599033Skettenis { "dcdc-reg7", 0x20, 0xff, 0, 0, rk806_vsel_range1 }, 169b8599033Skettenis { "dcdc-reg8", 0x21, 0xff, 0, 0, rk806_vsel_range1 }, 170b8599033Skettenis { "dcdc-reg9", 0x22, 0xff, 0, 0, rk806_vsel_range1 }, 171b8599033Skettenis { "dcdc-reg10", 0x23, 0xff, 0, 0, rk806_vsel_range1 }, 172b8599033Skettenis { "nldo-reg1", 0x43, 0xff, 0, 0, rk806_vsel_range2 }, 173b8599033Skettenis { "nldo-reg2", 0x44, 0xff, 0, 0, rk806_vsel_range2 }, 174b8599033Skettenis { "nldo-reg3", 0x45, 0xff, 0, 0, rk806_vsel_range2 }, 175b8599033Skettenis { "nldo-reg4", 0x46, 0xff, 0, 0, rk806_vsel_range2 }, 176b8599033Skettenis { "nldo-reg5", 0x47, 0xff, 0, 0, rk806_vsel_range2 }, 177b8599033Skettenis { "pldo-reg1", 0x4e, 0xff, 0, 0, rk806_vsel_range2 }, 178b8599033Skettenis { "pldo-reg2", 0x4f, 0xff, 0, 0, rk806_vsel_range2 }, 179b8599033Skettenis { "pldo-reg3", 0x50, 0xff, 0, 0, rk806_vsel_range2 }, 180b8599033Skettenis { "pldo-reg4", 0x51, 0xff, 0, 0, rk806_vsel_range2 }, 181b8599033Skettenis { "pldo-reg5", 0x52, 0xff, 0, 0, rk806_vsel_range2 }, 182b8599033Skettenis { "pldo-reg6", 0x53, 0xff, 0, 0, rk806_vsel_range2 }, 183ca857453Skettenis { } 184ca857453Skettenis }; 185ca857453Skettenis 186ca857453Skettenis /* 187c23d9011Skurt * Used by RK808 for BUCK1 & BUCK2 188c23d9011Skurt * 0-63: 0.7125V-1.5V, step=12.5mV 189c23d9011Skurt */ 19037c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range1[] = { 191c23d9011Skurt { 712500, 12500, 0, 63 }, 192c23d9011Skurt {} 193c23d9011Skurt }; 194c23d9011Skurt 195c23d9011Skurt /* 196c23d9011Skurt * Used by RK808 for BUCK4 197c23d9011Skurt * 0-15: 1.8V-3.3V,step=100mV 198c23d9011Skurt */ 19937c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range2[] = { 200c23d9011Skurt { 1800000, 100000, 0, 15 }, 201c23d9011Skurt {} 202c23d9011Skurt }; 203c23d9011Skurt 204c23d9011Skurt /* 205c23d9011Skurt * Used by RK808 for LDO1-2, 4-5, 8 206c23d9011Skurt * 0-16: 1.8V-3.4V, step=100mV 207c23d9011Skurt */ 20837c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range3[] = { 209c23d9011Skurt { 1800000, 100000, 0, 16 }, 210c23d9011Skurt {} 211c23d9011Skurt }; 212c23d9011Skurt 213c23d9011Skurt /* 214c23d9011Skurt * Used by RK808 for LDO3 215c23d9011Skurt * 0-12: 0.8V~2.0V, step=100mV 216c23d9011Skurt * 13: 2.2V 217c23d9011Skurt * 15: 2.5V 218c23d9011Skurt */ 21937c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range4[] = { 220c23d9011Skurt { 800000, 100000, 0, 12 }, 221c23d9011Skurt { 2200000, 0, 13, 13 }, 222c23d9011Skurt { 2500000, 0, 15, 15 }, 223c23d9011Skurt {} 224c23d9011Skurt }; 225c23d9011Skurt 226c23d9011Skurt /* 227c23d9011Skurt * Used by RK808 for LDO6-7 228c23d9011Skurt * 0-17: 0.8V-2.5V,step=100mV 229c23d9011Skurt */ 23037c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range5[] = { 231c23d9011Skurt { 800000, 100000, 0, 17 }, 23243f7f110Skettenis {} 23343f7f110Skettenis }; 23443f7f110Skettenis 23537c734d3Snaddy const struct rkpmic_regdata rk808_regdata[] = { 236b8599033Skettenis { "DCDC_REG1", 0x2f, 0x3f, 0, 0, rk808_vsel_range1 }, 237b8599033Skettenis { "DCDC_REG2", 0x33, 0x3f, 0, 0, rk808_vsel_range1 }, 238b8599033Skettenis { "DCDC_REG4", 0x38, 0x0f, 0, 0, rk808_vsel_range2 }, 239b8599033Skettenis { "LDO_REG1", 0x3b, 0x1f, 0, 0, rk808_vsel_range3 }, 240b8599033Skettenis { "LDO_REG2", 0x3d, 0x1f, 0, 0, rk808_vsel_range3 }, 241b8599033Skettenis { "LDO_REG3", 0x3f, 0x0f, 0, 0, rk808_vsel_range4 }, 242b8599033Skettenis { "LDO_REG4", 0x41, 0x1f, 0, 0, rk808_vsel_range3 }, 243b8599033Skettenis { "LDO_REG5", 0x43, 0x1f, 0, 0, rk808_vsel_range3 }, 244b8599033Skettenis { "LDO_REG6", 0x45, 0x1f, 0, 0, rk808_vsel_range5 }, 245b8599033Skettenis { "LDO_REG7", 0x47, 0x1f, 0, 0, rk808_vsel_range5 }, 246b8599033Skettenis { "LDO_REG8", 0x49, 0x1f, 0, 0, rk808_vsel_range3 }, 247c23d9011Skurt { } 248c23d9011Skurt }; 249c23d9011Skurt 250c23d9011Skurt /* 251c23d9011Skurt * Used by RK809 for BUCK1-3 252c23d9011Skurt * 0-80: 0.5V-1.5V,step=12.5mV 253c23d9011Skurt * 81-89: 1.6V-2.4V,step=100mV 254c23d9011Skurt */ 25537c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range1[] = { 256c23d9011Skurt { 500000, 12500, 0, 80 }, 257c23d9011Skurt { 1600000, 100000, 81, 89 }, 258c23d9011Skurt {} 259c23d9011Skurt }; 260c23d9011Skurt 261c23d9011Skurt /* 262c23d9011Skurt * Used by RK809 for BUCK4 263c23d9011Skurt * 0-80: 0.5V-1.5V,step=12.5mV 264c23d9011Skurt * 81-99: 1.6V-3.4V,step=100mV 265c23d9011Skurt */ 26637c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range2[] = { 267c23d9011Skurt { 500000, 12500, 0, 80 }, 268c23d9011Skurt { 1600000, 100000, 81, 99 }, 269c23d9011Skurt {} 270c23d9011Skurt }; 271c23d9011Skurt 272c23d9011Skurt /* 273c23d9011Skurt * Used by RK809 for BUCK5 274c23d9011Skurt * 0: 1.5V 275c23d9011Skurt * 1-3: 1.8V-2.2V,step=200mV 276c23d9011Skurt * 4-5: 2.8V-3.0V,step=200mV 277c23d9011Skurt * 6-7: 3.3V-3.6V,step=300mV 278c23d9011Skurt */ 27937c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range3[] = { 280c23d9011Skurt { 1500000, 0, 0, 0 }, 281c23d9011Skurt { 1800000, 200000, 1, 3 }, 282c23d9011Skurt { 2800000, 200000, 4, 5 }, 283c23d9011Skurt { 3300000, 300000, 6, 7 }, 284c23d9011Skurt {} 285c23d9011Skurt }; 286c23d9011Skurt 287c23d9011Skurt /* 288c23d9011Skurt * Used by RK809 for LDO1-7 289c23d9011Skurt * 0-112: 0.6V-3.4V,step=25mV 290c23d9011Skurt */ 29137c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range4[] = { 292c23d9011Skurt { 600000, 25000, 0, 112 }, 293c23d9011Skurt {} 294c23d9011Skurt }; 295c23d9011Skurt 29637c734d3Snaddy const struct rkpmic_regdata rk809_regdata[] = { 297b8599033Skettenis { "DCDC_REG1", 0xbb, 0x7f, 0xb5, 0x01, rk809_vsel_range1 }, 298b8599033Skettenis { "DCDC_REG2", 0xbe, 0x7f, 0xb5, 0x02, rk809_vsel_range1 }, 299b8599033Skettenis { "DCDC_REG3", 0xc1, 0x7f, 0xb5, 0x04, rk809_vsel_range1 }, 300b8599033Skettenis { "DCDC_REG4", 0xc4, 0x7f, 0xb5, 0x08, rk809_vsel_range2 }, 301b8599033Skettenis { "DCDC_REG5", 0xde, 0x0f, 0xb5, 0x20, rk809_vsel_range3 }, 302b8599033Skettenis { "LDO_REG1", 0xcc, 0x7f, 0xb6, 0x01, rk809_vsel_range4 }, 303b8599033Skettenis { "LDO_REG2", 0xce, 0x7f, 0xb6, 0x02, rk809_vsel_range4 }, 304b8599033Skettenis { "LDO_REG3", 0xd0, 0x7f, 0xb6, 0x04, rk809_vsel_range4 }, 305b8599033Skettenis { "LDO_REG4", 0xd2, 0x7f, 0xb6, 0x08, rk809_vsel_range4 }, 306b8599033Skettenis { "LDO_REG5", 0xd4, 0x7f, 0xb6, 0x10, rk809_vsel_range4 }, 307b8599033Skettenis { "LDO_REG6", 0xd6, 0x7f, 0xb6, 0x20, rk809_vsel_range4 }, 308b8599033Skettenis { "LDO_REG7", 0xd8, 0x7f, 0xb6, 0x40, rk809_vsel_range4 }, 309b8599033Skettenis { "LDO_REG8", 0xda, 0x7f, 0xb6, 0x80, rk809_vsel_range4 }, 310b8599033Skettenis { "LDO_REG9", 0xdc, 0x7f, 0xb5, 0x10, rk809_vsel_range4 }, 311b8599033Skettenis { "SWITCH_REG1", 0, 0, 0xb5, 0x40, NULL }, 312b8599033Skettenis { "SWITCH_REG2", 0, 0, 0xb5, 0x80, NULL }, 31343f7f110Skettenis { } 31492bce581Skettenis }; 31592bce581Skettenis 316725f2616Skettenis /* 317725f2616Skettenis * Used by RK817 for BOOST 318725f2616Skettenis * 0-7: 4.7V-5.4V,step=100mV 319725f2616Skettenis */ 320725f2616Skettenis const struct rkpmic_vsel_range rk817_boost_range[] = { 321725f2616Skettenis { 4700000, 100000, 0, 7 }, 322725f2616Skettenis {} 323725f2616Skettenis }; 324725f2616Skettenis 325725f2616Skettenis const struct rkpmic_regdata rk817_regdata[] = { 326b8599033Skettenis { "DCDC_REG1", 0xbb, 0x7f, 0, 0, rk809_vsel_range1 }, 327b8599033Skettenis { "DCDC_REG2", 0xbe, 0x7f, 0, 0, rk809_vsel_range1 }, 328b8599033Skettenis { "DCDC_REG3", 0xc1, 0x7f, 0, 0, rk809_vsel_range1 }, 329b8599033Skettenis { "DCDC_REG4", 0xc4, 0x7f, 0, 0, rk809_vsel_range2 }, 330b8599033Skettenis { "LDO_REG1", 0xcc, 0x7f, 0, 0, rk809_vsel_range4 }, 331b8599033Skettenis { "LDO_REG2", 0xce, 0x7f, 0, 0, rk809_vsel_range4 }, 332b8599033Skettenis { "LDO_REG3", 0xd0, 0x7f, 0, 0, rk809_vsel_range4 }, 333b8599033Skettenis { "LDO_REG4", 0xd2, 0x7f, 0, 0, rk809_vsel_range4 }, 334b8599033Skettenis { "LDO_REG5", 0xd4, 0x7f, 0, 0, rk809_vsel_range4 }, 335b8599033Skettenis { "LDO_REG6", 0xd6, 0x7f, 0, 0, rk809_vsel_range4 }, 336b8599033Skettenis { "LDO_REG7", 0xd8, 0x7f, 0, 0, rk809_vsel_range4 }, 337b8599033Skettenis { "LDO_REG8", 0xda, 0x7f, 0, 0, rk809_vsel_range4 }, 338b8599033Skettenis { "LDO_REG9", 0xdc, 0x7f, 0, 0, rk809_vsel_range4 }, 339b8599033Skettenis { "BOOST", 0xde, 0x07, 0, 0, rk817_boost_range }, 340725f2616Skettenis { } 341725f2616Skettenis }; 342725f2616Skettenis 343ad688f68Skettenis struct rkpmic_softc { 344ad688f68Skettenis struct device sc_dev; 345ca857453Skettenis int sc_node; 346ca857453Skettenis 347ca857453Skettenis i2c_tag_t sc_i2c_tag; 348ca857453Skettenis i2c_addr_t sc_i2c_addr; 349ca857453Skettenis spi_tag_t sc_spi_tag; 350ca857453Skettenis struct spi_config sc_spi_conf; 351ad688f68Skettenis 352c23d9011Skurt int sc_rtc_ctrl_reg, sc_rtc_status_reg; 353*32a67d49Skettenis uint8_t sc_dev_ctrl_reg, sc_dev_off_val; 354*32a67d49Skettenis 355ad688f68Skettenis struct todr_chip_handle sc_todr; 35637c734d3Snaddy const struct rkpmic_regdata *sc_regdata; 357ca857453Skettenis 358ca857453Skettenis int (*sc_read)(struct rkpmic_softc *, uint8_t, void *, size_t); 359ca857453Skettenis int (*sc_write)(struct rkpmic_softc *, uint8_t, void *, size_t); 36030293cdcSkettenis 36130293cdcSkettenis void *sc_ih; 362ad688f68Skettenis }; 363ad688f68Skettenis 364ca857453Skettenis int rkpmic_i2c_match(struct device *, void *, void *); 365ca857453Skettenis void rkpmic_i2c_attach(struct device *, struct device *, void *); 366ca857453Skettenis int rkpmic_i2c_read(struct rkpmic_softc *, uint8_t, void *, size_t); 367ca857453Skettenis int rkpmic_i2c_write(struct rkpmic_softc *, uint8_t, void *, size_t); 368ca857453Skettenis 369ca857453Skettenis int rkpmic_spi_match(struct device *, void *, void *); 370ca857453Skettenis void rkpmic_spi_attach(struct device *, struct device *, void *); 371ca857453Skettenis int rkpmic_spi_read(struct rkpmic_softc *, uint8_t, void *, size_t); 372ca857453Skettenis int rkpmic_spi_write(struct rkpmic_softc *, uint8_t, void *, size_t); 373ca857453Skettenis 374ad688f68Skettenis void rkpmic_attach(struct device *, struct device *, void *); 37530293cdcSkettenis int rkpmic_activate(struct device *, int); 376ad688f68Skettenis 377ca857453Skettenis const struct cfattach rkpmic_i2c_ca = { 37830293cdcSkettenis sizeof(struct rkpmic_softc), rkpmic_i2c_match, rkpmic_i2c_attach, 37930293cdcSkettenis NULL, rkpmic_activate 380ca857453Skettenis }; 381ca857453Skettenis 382ca857453Skettenis const struct cfattach rkpmic_spi_ca = { 383ca857453Skettenis sizeof(struct rkpmic_softc), rkpmic_spi_match, rkpmic_spi_attach 384ad688f68Skettenis }; 385ad688f68Skettenis 386ad688f68Skettenis struct cfdriver rkpmic_cd = { 387ad688f68Skettenis NULL, "rkpmic", DV_DULL 388ad688f68Skettenis }; 389ad688f68Skettenis 39030293cdcSkettenis int rkpmic_intr(void *); 39192bce581Skettenis void rkpmic_attach_regulator(struct rkpmic_softc *, int); 392ad688f68Skettenis uint8_t rkpmic_reg_read(struct rkpmic_softc *, int); 393ad688f68Skettenis void rkpmic_reg_write(struct rkpmic_softc *, int, uint8_t); 394ad688f68Skettenis int rkpmic_clock_read(struct rkpmic_softc *, struct clock_ymdhms *); 395ad688f68Skettenis int rkpmic_clock_write(struct rkpmic_softc *, struct clock_ymdhms *); 396ad688f68Skettenis int rkpmic_gettime(struct todr_chip_handle *, struct timeval *); 397ad688f68Skettenis int rkpmic_settime(struct todr_chip_handle *, struct timeval *); 398ad688f68Skettenis 399*32a67d49Skettenis struct rkpmic_softc *rkpmic_sc; 400*32a67d49Skettenis void rkpmic_powerdown(void); 401*32a67d49Skettenis 402ad688f68Skettenis int 403ca857453Skettenis rkpmic_i2c_match(struct device *parent, void *match, void *aux) 404ad688f68Skettenis { 405ad688f68Skettenis struct i2c_attach_args *ia = aux; 406ad688f68Skettenis 4071ac62f4eSpatrick return (strcmp(ia->ia_name, "rockchip,rk805") == 0 || 408c23d9011Skurt strcmp(ia->ia_name, "rockchip,rk808") == 0 || 409725f2616Skettenis strcmp(ia->ia_name, "rockchip,rk809") == 0 || 410725f2616Skettenis strcmp(ia->ia_name, "rockchip,rk817") == 0); 411ad688f68Skettenis } 412ad688f68Skettenis 413ad688f68Skettenis void 414ca857453Skettenis rkpmic_i2c_attach(struct device *parent, struct device *self, void *aux) 415ad688f68Skettenis { 416ad688f68Skettenis struct rkpmic_softc *sc = (struct rkpmic_softc *)self; 417ad688f68Skettenis struct i2c_attach_args *ia = aux; 418ca857453Skettenis 419ca857453Skettenis sc->sc_i2c_tag = ia->ia_tag; 420ca857453Skettenis sc->sc_i2c_addr = ia->ia_addr; 421ca857453Skettenis sc->sc_node = *(int *)ia->ia_cookie; 422ca857453Skettenis sc->sc_read = rkpmic_i2c_read; 423ca857453Skettenis sc->sc_write = rkpmic_i2c_write; 424ca857453Skettenis 425ca857453Skettenis rkpmic_attach(parent, self, aux); 426ca857453Skettenis } 427ca857453Skettenis 428ca857453Skettenis int 429ca857453Skettenis rkpmic_spi_match(struct device *parent, void *match, void *aux) 430ca857453Skettenis { 431ca857453Skettenis struct spi_attach_args *sa = aux; 432ca857453Skettenis 433ca857453Skettenis return (strcmp(sa->sa_name, "rockchip,rk806") == 0); 434ca857453Skettenis } 435ca857453Skettenis 436ca857453Skettenis void 437ca857453Skettenis rkpmic_spi_attach(struct device *parent, struct device *self, void *aux) 438ca857453Skettenis { 439ca857453Skettenis struct rkpmic_softc *sc = (struct rkpmic_softc *)self; 440ca857453Skettenis struct spi_attach_args *sa = aux; 441ca857453Skettenis 442ca857453Skettenis sc->sc_spi_tag = sa->sa_tag; 443ca857453Skettenis sc->sc_node = *(int *)sa->sa_cookie; 444ca857453Skettenis sc->sc_read = rkpmic_spi_read; 445ca857453Skettenis sc->sc_write = rkpmic_spi_write; 446ca857453Skettenis 447ca857453Skettenis sc->sc_spi_conf.sc_bpw = 8; 448ca857453Skettenis sc->sc_spi_conf.sc_freq = 449ca857453Skettenis OF_getpropint(sc->sc_node, "spi-max-frequency", 1000000); 450ca857453Skettenis sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0); 451ca857453Skettenis 452ca857453Skettenis rkpmic_attach(parent, self, aux); 453ca857453Skettenis } 454ca857453Skettenis 455ca857453Skettenis void 456ca857453Skettenis rkpmic_attach(struct device *parent, struct device *self, void *aux) 457ca857453Skettenis { 458ca857453Skettenis struct rkpmic_softc *sc = (struct rkpmic_softc *)self; 45943f7f110Skettenis const char *chip; 46030293cdcSkettenis uint8_t val; 461ca857453Skettenis int node; 462ad688f68Skettenis 463ca857453Skettenis if (OF_is_compatible(sc->sc_node, "rockchip,rk805")) { 46443f7f110Skettenis chip = "RK805"; 465c23d9011Skurt sc->sc_rtc_ctrl_reg = RK805_RTC_CTRL; 466c23d9011Skurt sc->sc_rtc_status_reg = RK805_RTC_STATUS; 467*32a67d49Skettenis sc->sc_dev_ctrl_reg = RK805_DEV_CTRL; 468*32a67d49Skettenis sc->sc_dev_off_val = RK805_DEV_CTRL_DEV_OFF; 46943f7f110Skettenis sc->sc_regdata = rk805_regdata; 470ca857453Skettenis } else if (OF_is_compatible(sc->sc_node, "rockchip,rk806")) { 471ca857453Skettenis chip = "RK806"; 472*32a67d49Skettenis sc->sc_dev_ctrl_reg = RK806_SYS_CFG3; 473*32a67d49Skettenis sc->sc_dev_off_val = RK806_SYS_CFG3_DEV_OFF; 474ca857453Skettenis sc->sc_regdata = rk806_regdata; 475ca857453Skettenis } else if (OF_is_compatible(sc->sc_node, "rockchip,rk808")) { 47643f7f110Skettenis chip = "RK808"; 477c23d9011Skurt sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL; 478c23d9011Skurt sc->sc_rtc_status_reg = RK808_RTC_STATUS; 479*32a67d49Skettenis sc->sc_dev_ctrl_reg = RK808_DEVCTRL; 480*32a67d49Skettenis sc->sc_dev_off_val = RK808_DEVCTRL_DEV_OFF_RST; 48143f7f110Skettenis sc->sc_regdata = rk808_regdata; 482ca857453Skettenis } else if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) { 483c23d9011Skurt chip = "RK809"; 484c23d9011Skurt sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; 485c23d9011Skurt sc->sc_rtc_status_reg = RK809_RTC_STATUS; 486*32a67d49Skettenis sc->sc_dev_ctrl_reg = RK809_PMIC_SYS_CFG3; 487*32a67d49Skettenis sc->sc_dev_off_val = RK809_PMIC_SYS_CFG3_DEV_OFF; 488c23d9011Skurt sc->sc_regdata = rk809_regdata; 489725f2616Skettenis } else { 490725f2616Skettenis chip = "RK817"; 491725f2616Skettenis sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; 492725f2616Skettenis sc->sc_rtc_status_reg = RK809_RTC_STATUS; 493*32a67d49Skettenis sc->sc_dev_ctrl_reg = RK809_PMIC_SYS_CFG3; 494*32a67d49Skettenis sc->sc_dev_off_val = RK809_PMIC_SYS_CFG3_DEV_OFF; 495725f2616Skettenis sc->sc_regdata = rk817_regdata; 49643f7f110Skettenis } 49743f7f110Skettenis printf(": %s\n", chip); 49843f7f110Skettenis 499ca857453Skettenis if (sc->sc_rtc_ctrl_reg) { 500ca857453Skettenis sc->sc_todr.cookie = sc; 501ca857453Skettenis sc->sc_todr.todr_gettime = rkpmic_gettime; 502ca857453Skettenis sc->sc_todr.todr_settime = rkpmic_settime; 503ca857453Skettenis sc->sc_todr.todr_quality = 0; 504ca857453Skettenis todr_attach(&sc->sc_todr); 505ca857453Skettenis } 506ca857453Skettenis 507ca857453Skettenis node = OF_getnodebyname(sc->sc_node, "regulators"); 50892bce581Skettenis if (node == 0) 50992bce581Skettenis return; 51092bce581Skettenis for (node = OF_child(node); node; node = OF_peer(node)) 51192bce581Skettenis rkpmic_attach_regulator(sc, node); 51230293cdcSkettenis 51330293cdcSkettenis if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) { 51430293cdcSkettenis /* Mask all interrupts. */ 51530293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_MSK0, 0xff); 51630293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_MSK1, 0xff); 51730293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_MSK2, 0xff); 51830293cdcSkettenis 51930293cdcSkettenis /* Ack all interrupts. */ 52030293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_STS0, 0xff); 52130293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_STS1, 0xff); 52230293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_STS2, 0xff); 52330293cdcSkettenis 52430293cdcSkettenis /* Set interrupt pin to active-low. */ 52530293cdcSkettenis val = rkpmic_reg_read(sc, RK809_PMIC_GPIO_INT_CONFIG); 52630293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_GPIO_INT_CONFIG, 52730293cdcSkettenis val & ~RK809_PMIC_GPIO_INT_CONFIG_INT_POL); 52830293cdcSkettenis 52930293cdcSkettenis sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_TTY, 53030293cdcSkettenis rkpmic_intr, sc, sc->sc_dev.dv_xname); 53130293cdcSkettenis 53230293cdcSkettenis /* Unmask power button interrupt. */ 53330293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_MSK0, 53430293cdcSkettenis ~RK809_PMIC_INT_MSK0_PWRON_FALL_INT_IM); 53530293cdcSkettenis 53630293cdcSkettenis #ifdef SUSPEND 53730293cdcSkettenis if (OF_getpropbool(sc->sc_node, "wakeup-source")) 53830293cdcSkettenis device_register_wakeup(&sc->sc_dev); 53930293cdcSkettenis #endif 54030293cdcSkettenis } 541*32a67d49Skettenis 542*32a67d49Skettenis if (OF_getpropbool(sc->sc_node, "system-power-controller") || 543*32a67d49Skettenis OF_getpropbool(sc->sc_node, "rockchip,system-power-controller")) { 544*32a67d49Skettenis rkpmic_sc = sc; 545*32a67d49Skettenis powerdownfn = rkpmic_powerdown; 546*32a67d49Skettenis } 54730293cdcSkettenis } 54830293cdcSkettenis 54930293cdcSkettenis int 55030293cdcSkettenis rkpmic_activate(struct device *self, int act) 55130293cdcSkettenis { 55230293cdcSkettenis struct rkpmic_softc *sc = (struct rkpmic_softc *)self; 55330293cdcSkettenis uint8_t val; 55430293cdcSkettenis 55530293cdcSkettenis switch (act) { 55630293cdcSkettenis case DVACT_SUSPEND: 55730293cdcSkettenis if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) { 55830293cdcSkettenis val = rkpmic_reg_read(sc, RK809_PMIC_SYS_CFG3); 55930293cdcSkettenis val &= ~RK809_PMIC_SYS_CFG3_SLP_FUN_MASK; 56030293cdcSkettenis val |= RK809_PMIC_SYS_CFG3_SLP_FUN_SLEEP; 56130293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_SYS_CFG3, val); 56230293cdcSkettenis } 56330293cdcSkettenis break; 56430293cdcSkettenis case DVACT_RESUME: 56530293cdcSkettenis if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) { 56630293cdcSkettenis val = rkpmic_reg_read(sc, RK809_PMIC_SYS_CFG3); 56730293cdcSkettenis val &= ~RK809_PMIC_SYS_CFG3_SLP_FUN_MASK; 56830293cdcSkettenis val |= RK809_PMIC_SYS_CFG3_SLP_FUN_NONE; 56930293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_SYS_CFG3, val); 570456d6666Skettenis rkpmic_reg_write(sc, RK809_PMIC_INT_STS0, 0xff); 57130293cdcSkettenis } 57230293cdcSkettenis break; 57330293cdcSkettenis } 57430293cdcSkettenis 57530293cdcSkettenis return 0; 57630293cdcSkettenis } 57730293cdcSkettenis 57830293cdcSkettenis int 57930293cdcSkettenis rkpmic_intr(void *arg) 58030293cdcSkettenis { 58130293cdcSkettenis extern int allowpowerdown; 58230293cdcSkettenis struct rkpmic_softc *sc = arg; 58330293cdcSkettenis 58430293cdcSkettenis if (allowpowerdown) { 58530293cdcSkettenis allowpowerdown = 0; 58630293cdcSkettenis prsignal(initprocess, SIGUSR2); 58730293cdcSkettenis } 58830293cdcSkettenis 58930293cdcSkettenis rkpmic_reg_write(sc, RK809_PMIC_INT_STS0, 0xff); 59030293cdcSkettenis return 1; 59192bce581Skettenis } 59292bce581Skettenis 593*32a67d49Skettenis void 594*32a67d49Skettenis rkpmic_powerdown(void) 595*32a67d49Skettenis { 596*32a67d49Skettenis struct rkpmic_softc *sc = rkpmic_sc; 597*32a67d49Skettenis rkpmic_reg_write(sc, sc->sc_dev_ctrl_reg, 598*32a67d49Skettenis rkpmic_reg_read(sc, sc->sc_dev_ctrl_reg) | sc->sc_dev_off_val); 599*32a67d49Skettenis } 600*32a67d49Skettenis 60192bce581Skettenis struct rkpmic_regulator { 60292bce581Skettenis struct rkpmic_softc *rr_sc; 60392bce581Skettenis 604b8599033Skettenis uint8_t rr_vreg, rr_vmask; 60537c734d3Snaddy const struct rkpmic_vsel_range *rr_vsel_range; 60692bce581Skettenis 60792bce581Skettenis struct regulator_device rr_rd; 60892bce581Skettenis }; 60992bce581Skettenis 61092bce581Skettenis uint32_t rkpmic_get_voltage(void *); 611db6014e5Skettenis int rkpmic_set_voltage(void *, uint32_t); 612b8599033Skettenis int rkpmic_do_set_voltage(struct rkpmic_regulator *, uint32_t, int); 61392bce581Skettenis 61492bce581Skettenis void 61592bce581Skettenis rkpmic_attach_regulator(struct rkpmic_softc *sc, int node) 61692bce581Skettenis { 61792bce581Skettenis struct rkpmic_regulator *rr; 61892bce581Skettenis char name[32]; 619b8599033Skettenis uint32_t voltage; 620b8599033Skettenis int i, snode; 621b8599033Skettenis uint8_t val; 62292bce581Skettenis 62392bce581Skettenis name[0] = 0; 62492bce581Skettenis OF_getprop(node, "name", name, sizeof(name)); 62592bce581Skettenis name[sizeof(name) - 1] = 0; 62643f7f110Skettenis for (i = 0; sc->sc_regdata[i].name; i++) { 62743f7f110Skettenis if (strcmp(sc->sc_regdata[i].name, name) == 0) 62892bce581Skettenis break; 62992bce581Skettenis } 63043f7f110Skettenis if (sc->sc_regdata[i].name == NULL) 63192bce581Skettenis return; 63292bce581Skettenis 63392bce581Skettenis rr = malloc(sizeof(*rr), M_DEVBUF, M_WAITOK | M_ZERO); 63492bce581Skettenis rr->rr_sc = sc; 63592bce581Skettenis 636b8599033Skettenis rr->rr_vreg = sc->sc_regdata[i].vreg; 637b8599033Skettenis rr->rr_vmask = sc->sc_regdata[i].vmask; 638c23d9011Skurt rr->rr_vsel_range = sc->sc_regdata[i].vsel_range; 63992bce581Skettenis 64092bce581Skettenis rr->rr_rd.rd_node = node; 64192bce581Skettenis rr->rr_rd.rd_cookie = rr; 64292bce581Skettenis rr->rr_rd.rd_get_voltage = rkpmic_get_voltage; 643db6014e5Skettenis rr->rr_rd.rd_set_voltage = rkpmic_set_voltage; 64492bce581Skettenis regulator_register(&rr->rr_rd); 645b8599033Skettenis 646b8599033Skettenis if (sc->sc_regdata[i].smask) { 647b8599033Skettenis snode = OF_getnodebyname(node, "regulator-state-mem"); 648b8599033Skettenis if (snode) { 649b8599033Skettenis val = rkpmic_reg_read(sc, sc->sc_regdata[i].sreg); 650b8599033Skettenis if (OF_getpropbool(snode, "regulator-on-in-suspend")) 651b8599033Skettenis val |= sc->sc_regdata[i].smask; 652b8599033Skettenis if (OF_getpropbool(snode, "regulator-off-in-suspend")) 653b8599033Skettenis val &= ~sc->sc_regdata[i].smask; 654b8599033Skettenis rkpmic_reg_write(sc, sc->sc_regdata[i].sreg, val); 655b8599033Skettenis 656b8599033Skettenis voltage = OF_getpropint(snode, 657b8599033Skettenis "regulator-suspend-min-microvolt", 0); 658b8599033Skettenis voltage = OF_getpropint(snode, 659b8599033Skettenis "regulator-suspend-microvolt", voltage); 660b8599033Skettenis if (voltage > 0) 661b8599033Skettenis rkpmic_do_set_voltage(rr, voltage, 1); 662b8599033Skettenis } 663b8599033Skettenis } 66492bce581Skettenis } 66592bce581Skettenis 66692bce581Skettenis uint32_t 66792bce581Skettenis rkpmic_get_voltage(void *cookie) 66892bce581Skettenis { 66992bce581Skettenis struct rkpmic_regulator *rr = cookie; 67037c734d3Snaddy const struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range; 671db6014e5Skettenis uint8_t vsel; 672c23d9011Skurt uint32_t ret = 0; 67392bce581Skettenis 674b8599033Skettenis if (vsel_range == NULL) 675b8599033Skettenis return 0; 676b8599033Skettenis 677b8599033Skettenis vsel = rkpmic_reg_read(rr->rr_sc, rr->rr_vreg) & rr->rr_vmask; 678c23d9011Skurt 679c23d9011Skurt while (vsel_range->base) { 680c23d9011Skurt ret = vsel_range->base; 681c23d9011Skurt if (vsel >= vsel_range->vsel_min && 682c23d9011Skurt vsel <= vsel_range->vsel_max) { 683c23d9011Skurt ret += (vsel - vsel_range->vsel_min) * 684c23d9011Skurt vsel_range->delta; 685c23d9011Skurt break; 686c23d9011Skurt } else 687c23d9011Skurt ret += (vsel_range->vsel_max - vsel_range->vsel_min) * 688c23d9011Skurt vsel_range->delta; 689c23d9011Skurt vsel_range++; 690c23d9011Skurt 691c23d9011Skurt } 692c23d9011Skurt 693c23d9011Skurt return ret; 694db6014e5Skettenis } 695db6014e5Skettenis 696db6014e5Skettenis int 697db6014e5Skettenis rkpmic_set_voltage(void *cookie, uint32_t voltage) 698db6014e5Skettenis { 699b8599033Skettenis return rkpmic_do_set_voltage(cookie, voltage, 0); 700b8599033Skettenis } 701b8599033Skettenis 702b8599033Skettenis int 703b8599033Skettenis rkpmic_do_set_voltage(struct rkpmic_regulator *rr, uint32_t voltage, int sleep) 704b8599033Skettenis { 70537c734d3Snaddy const struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range; 706c23d9011Skurt uint32_t vmin, vmax, volt; 707c23d9011Skurt uint8_t reg, vsel; 708db6014e5Skettenis 709b8599033Skettenis if (vsel_range == NULL) 710b8599033Skettenis return ENODEV; 711b8599033Skettenis 712c23d9011Skurt while (vsel_range->base) { 713c23d9011Skurt vmin = vsel_range->base; 714c23d9011Skurt vmax = vmin + (vsel_range->vsel_max - vsel_range->vsel_min) * 715c23d9011Skurt vsel_range->delta; 716c23d9011Skurt if (voltage < vmin) 717c23d9011Skurt return EINVAL; 718c23d9011Skurt if (voltage <= vmax) { 719c23d9011Skurt vsel = vsel_range->vsel_min; 720c23d9011Skurt volt = vsel_range->base; 721c23d9011Skurt while (vsel <= vsel_range->vsel_max) { 722c23d9011Skurt if (volt == voltage) 723c23d9011Skurt break; 724c23d9011Skurt else { 725c23d9011Skurt vsel++; 726c23d9011Skurt volt += vsel_range->delta; 727c23d9011Skurt } 728c23d9011Skurt } 729c23d9011Skurt if (volt != voltage) 730c23d9011Skurt return EINVAL; 731c23d9011Skurt break; 732c23d9011Skurt } 733c23d9011Skurt vsel_range++; 734c23d9011Skurt } 735c23d9011Skurt 736c23d9011Skurt if (vsel_range->base == 0) 737db6014e5Skettenis return EINVAL; 738db6014e5Skettenis 739b8599033Skettenis reg = rkpmic_reg_read(rr->rr_sc, rr->rr_vreg + sleep); 740b8599033Skettenis reg &= ~rr->rr_vmask; 741c23d9011Skurt reg |= vsel; 742b8599033Skettenis rkpmic_reg_write(rr->rr_sc, rr->rr_vreg + sleep, reg); 743db6014e5Skettenis 744db6014e5Skettenis return 0; 745ad688f68Skettenis } 746ad688f68Skettenis 747ad688f68Skettenis int 748ad688f68Skettenis rkpmic_gettime(struct todr_chip_handle *handle, struct timeval *tv) 749ad688f68Skettenis { 750ad688f68Skettenis struct rkpmic_softc *sc = handle->cookie; 751ad688f68Skettenis struct clock_ymdhms dt; 752ad688f68Skettenis time_t secs; 753ad688f68Skettenis int error; 754ad688f68Skettenis 755ad688f68Skettenis error = rkpmic_clock_read(sc, &dt); 756ad688f68Skettenis if (error) 757ad688f68Skettenis return error; 758ad688f68Skettenis 759ad688f68Skettenis if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || 760ad688f68Skettenis dt.dt_day > 31 || dt.dt_day == 0 || 761ad688f68Skettenis dt.dt_mon > 12 || dt.dt_mon == 0 || 762ad688f68Skettenis dt.dt_year < POSIX_BASE_YEAR) 763ad688f68Skettenis return EINVAL; 764ad688f68Skettenis 765ad688f68Skettenis /* 766ad688f68Skettenis * The RTC thinks November has 31 days. Match what Linux does 7679bec9e43Sjsg * and undo the damage by considering the calendars to be in 768ad688f68Skettenis * sync on January 1st 2016. 769ad688f68Skettenis */ 770ad688f68Skettenis secs = clock_ymdhms_to_secs(&dt); 771ad688f68Skettenis secs += (dt.dt_year - 2016 + (dt.dt_mon == 12 ? 1 : 0)) * 86400; 772ad688f68Skettenis 773ad688f68Skettenis tv->tv_sec = secs; 774ad688f68Skettenis tv->tv_usec = 0; 775ad688f68Skettenis return 0; 776ad688f68Skettenis } 777ad688f68Skettenis 778ad688f68Skettenis int 779ad688f68Skettenis rkpmic_settime(struct todr_chip_handle *handle, struct timeval *tv) 780ad688f68Skettenis { 781ad688f68Skettenis struct rkpmic_softc *sc = handle->cookie; 782ad688f68Skettenis struct clock_ymdhms dt; 783ad688f68Skettenis time_t secs; 784ad688f68Skettenis 785ad688f68Skettenis /* 78610770a61Sjasper * Take care of the November 31st braindamage here as well. 787ad688f68Skettenis * Don't try to be clever, just do the conversion in two 788ad688f68Skettenis * steps, first taking care of November 31 in previous years, 789ad688f68Skettenis * and then taking care of days in December of the current 7909bec9e43Sjsg * year. December 1st turns into November 31st! 791ad688f68Skettenis */ 792ad688f68Skettenis secs = tv->tv_sec; 793ad688f68Skettenis clock_secs_to_ymdhms(secs, &dt); 794ad688f68Skettenis secs -= (dt.dt_year - 2016) * 86400; 795ad688f68Skettenis clock_secs_to_ymdhms(secs, &dt); 796ad688f68Skettenis if (dt.dt_mon == 12) { 797ad688f68Skettenis dt.dt_day--; 798ad688f68Skettenis if (dt.dt_day == 0) { 799ad688f68Skettenis dt.dt_mon = 11; 800ad688f68Skettenis dt.dt_day = 31; 801ad688f68Skettenis } 802ad688f68Skettenis } 803ad688f68Skettenis 804ad688f68Skettenis return rkpmic_clock_write(sc, &dt); 805ad688f68Skettenis } 806ad688f68Skettenis 807ad688f68Skettenis uint8_t 808ad688f68Skettenis rkpmic_reg_read(struct rkpmic_softc *sc, int reg) 809ad688f68Skettenis { 810ad688f68Skettenis uint8_t cmd = reg; 811ad688f68Skettenis uint8_t val; 812ad688f68Skettenis 813ca857453Skettenis if (sc->sc_read(sc, cmd, &val, sizeof(val))) { 814ad688f68Skettenis printf("%s: can't read register 0x%02x\n", 815ad688f68Skettenis sc->sc_dev.dv_xname, reg); 816ad688f68Skettenis val = 0xff; 817ad688f68Skettenis } 818ad688f68Skettenis 819ad688f68Skettenis return val; 820ad688f68Skettenis } 821ad688f68Skettenis 822ad688f68Skettenis void 823ad688f68Skettenis rkpmic_reg_write(struct rkpmic_softc *sc, int reg, uint8_t val) 824ad688f68Skettenis { 825ad688f68Skettenis uint8_t cmd = reg; 826ad688f68Skettenis 827ca857453Skettenis if (sc->sc_write(sc, cmd, &val, sizeof(val))) { 828ad688f68Skettenis printf("%s: can't write register 0x%02x\n", 829ad688f68Skettenis sc->sc_dev.dv_xname, reg); 830ad688f68Skettenis } 831ad688f68Skettenis } 832ad688f68Skettenis 833ad688f68Skettenis int 834ad688f68Skettenis rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt) 835ad688f68Skettenis { 836c23d9011Skurt uint8_t regs[RK80X_NRTC_REGS]; 837c23d9011Skurt uint8_t cmd = RK80X_SECONDS; 838ad688f68Skettenis uint8_t status; 839ad688f68Skettenis int error; 840ad688f68Skettenis 841ca857453Skettenis error = sc->sc_read(sc, cmd, regs, RK80X_NRTC_REGS); 842ad688f68Skettenis 843ad688f68Skettenis if (error) { 844ad688f68Skettenis printf("%s: can't read RTC\n", sc->sc_dev.dv_xname); 845ad688f68Skettenis return error; 846ad688f68Skettenis } 847ad688f68Skettenis 848ad688f68Skettenis /* 849c23d9011Skurt * Convert the RK80x's register values into something useable. 850ad688f68Skettenis */ 851ad688f68Skettenis dt->dt_sec = FROMBCD(regs[0]); 852ad688f68Skettenis dt->dt_min = FROMBCD(regs[1]); 853ad688f68Skettenis dt->dt_hour = FROMBCD(regs[2]); 854ad688f68Skettenis dt->dt_day = FROMBCD(regs[3]); 855ad688f68Skettenis dt->dt_mon = FROMBCD(regs[4]); 856ad688f68Skettenis dt->dt_year = FROMBCD(regs[5]) + 2000; 857ad688f68Skettenis 858ad688f68Skettenis /* Consider the time to be invalid if the POWER_UP bit is set. */ 859c23d9011Skurt status = rkpmic_reg_read(sc, sc->sc_rtc_status_reg); 860c23d9011Skurt if (status & RK80X_RTC_STATUS_POWER_UP) 861ad688f68Skettenis return EINVAL; 862ad688f68Skettenis 863ad688f68Skettenis return 0; 864ad688f68Skettenis } 865ad688f68Skettenis 866ad688f68Skettenis int 867ad688f68Skettenis rkpmic_clock_write(struct rkpmic_softc *sc, struct clock_ymdhms *dt) 868ad688f68Skettenis { 869c23d9011Skurt uint8_t regs[RK80X_NRTC_REGS]; 870c23d9011Skurt uint8_t cmd = RK80X_SECONDS; 871ad688f68Skettenis int error; 872ad688f68Skettenis 873ad688f68Skettenis /* 874c23d9011Skurt * Convert our time representation into something the RK80x 875ad688f68Skettenis * can understand. 876ad688f68Skettenis */ 877ad688f68Skettenis regs[0] = TOBCD(dt->dt_sec); 878ad688f68Skettenis regs[1] = TOBCD(dt->dt_min); 879ad688f68Skettenis regs[2] = TOBCD(dt->dt_hour); 880ad688f68Skettenis regs[3] = TOBCD(dt->dt_day); 881ad688f68Skettenis regs[4] = TOBCD(dt->dt_mon); 882ad688f68Skettenis regs[5] = TOBCD(dt->dt_year - 2000); 883ad688f68Skettenis regs[6] = TOBCD(dt->dt_wday); 884ad688f68Skettenis 885ad688f68Skettenis /* Stop RTC such that we can write to it. */ 886c23d9011Skurt rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, RK80X_RTC_CTRL_STOP_RTC); 887ad688f68Skettenis 888ca857453Skettenis error = sc->sc_write(sc, cmd, regs, RK80X_NRTC_REGS); 889ad688f68Skettenis 890ad688f68Skettenis /* Restart RTC. */ 891c23d9011Skurt rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, 0); 892ad688f68Skettenis 893ad688f68Skettenis if (error) { 894ad688f68Skettenis printf("%s: can't write RTC\n", sc->sc_dev.dv_xname); 895ad688f68Skettenis return error; 896ad688f68Skettenis } 897ad688f68Skettenis 898ad688f68Skettenis /* Clear POWER_UP bit to indicate the time is now valid. */ 899c23d9011Skurt rkpmic_reg_write(sc, sc->sc_rtc_status_reg, RK80X_RTC_STATUS_POWER_UP); 900ad688f68Skettenis 901ad688f68Skettenis return 0; 902ad688f68Skettenis } 903ca857453Skettenis 904ca857453Skettenis int 905ca857453Skettenis rkpmic_i2c_read(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen) 906ca857453Skettenis { 907ca857453Skettenis int error; 908ca857453Skettenis 909ca857453Skettenis iic_acquire_bus(sc->sc_i2c_tag, I2C_F_POLL); 910ca857453Skettenis error = iic_exec(sc->sc_i2c_tag, I2C_OP_READ_WITH_STOP, 911ca857453Skettenis sc->sc_i2c_addr, &cmd, sizeof(cmd), buf, buflen, I2C_F_POLL); 912ca857453Skettenis iic_release_bus(sc->sc_i2c_tag, I2C_F_POLL); 913ca857453Skettenis 914ca857453Skettenis return error; 915ca857453Skettenis } 916ca857453Skettenis 917ca857453Skettenis int 918ca857453Skettenis rkpmic_i2c_write(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen) 919ca857453Skettenis { 920ca857453Skettenis int error; 921ca857453Skettenis 922ca857453Skettenis iic_acquire_bus(sc->sc_i2c_tag, I2C_F_POLL); 923ca857453Skettenis error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP, 924ca857453Skettenis sc->sc_i2c_addr, &cmd, sizeof(cmd), buf, buflen, I2C_F_POLL); 925ca857453Skettenis iic_release_bus(sc->sc_i2c_tag, I2C_F_POLL); 926ca857453Skettenis 927ca857453Skettenis return error; 928ca857453Skettenis } 929ca857453Skettenis 930ca857453Skettenis int 931ca857453Skettenis rkpmic_spi_read(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen) 932ca857453Skettenis { 933ca857453Skettenis uint8_t cmdbuf[3]; 934ca857453Skettenis int error; 935ca857453Skettenis 936ca857453Skettenis cmdbuf[0] = RKSPI_CMD_READ | (buflen - 1); 937ca857453Skettenis cmdbuf[1] = cmd; /* 16-bit addr low */ 938ca857453Skettenis cmdbuf[2] = 0x00; /* 16-bit addr high */ 939ca857453Skettenis 940ca857453Skettenis spi_acquire_bus(sc->sc_spi_tag, 0); 941ca857453Skettenis spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 942ca857453Skettenis error = spi_transfer(sc->sc_spi_tag, cmdbuf, NULL, sizeof(cmdbuf), 943ca857453Skettenis SPI_KEEP_CS); 944ca857453Skettenis if (!error) 945ca857453Skettenis error = spi_read(sc->sc_spi_tag, buf, buflen); 946ca857453Skettenis spi_release_bus(sc->sc_spi_tag, 0); 947ca857453Skettenis 948ca857453Skettenis return error; 949ca857453Skettenis } 950ca857453Skettenis 951ca857453Skettenis int 952ca857453Skettenis rkpmic_spi_write(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen) 953ca857453Skettenis { 954ca857453Skettenis uint8_t cmdbuf[3]; 955ca857453Skettenis int error; 956ca857453Skettenis 957ca857453Skettenis cmdbuf[0] = RKSPI_CMD_WRITE | (buflen - 1); 958ca857453Skettenis cmdbuf[1] = cmd; /* 16-bit addr low */ 959ca857453Skettenis cmdbuf[2] = 0x00; /* 16-bit addr high */ 960ca857453Skettenis 961ca857453Skettenis spi_acquire_bus(sc->sc_spi_tag, 0); 962ca857453Skettenis spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 963ca857453Skettenis error = spi_transfer(sc->sc_spi_tag, cmdbuf, NULL, sizeof(cmdbuf), 964ca857453Skettenis SPI_KEEP_CS); 965ca857453Skettenis if (!error) 966ca857453Skettenis error = spi_write(sc->sc_spi_tag, buf, buflen); 967ca857453Skettenis spi_release_bus(sc->sc_spi_tag, 0); 968ca857453Skettenis 969ca857453Skettenis return error; 970ca857453Skettenis } 971