1*3b536516Sjsg /* $OpenBSD: axppmic.c,v 1.21 2024/10/06 03:46:48 jsg Exp $ */ 2b393861dSkettenis /* 3b393861dSkettenis * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> 4b393861dSkettenis * 5b393861dSkettenis * Permission to use, copy, modify, and distribute this software for any 6b393861dSkettenis * purpose with or without fee is hereby granted, provided that the above 7b393861dSkettenis * copyright notice and this permission notice appear in all copies. 8b393861dSkettenis * 9b393861dSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10b393861dSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11b393861dSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12b393861dSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13b393861dSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14b393861dSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15b393861dSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16b393861dSkettenis */ 17b393861dSkettenis 18b393861dSkettenis #include <sys/param.h> 19b393861dSkettenis #include <sys/systm.h> 20b393861dSkettenis #include <sys/device.h> 21b393861dSkettenis #include <sys/malloc.h> 22de7daf7eSkettenis #include <sys/sensors.h> 23b393861dSkettenis 24de7daf7eSkettenis #include <dev/i2c/i2cvar.h> 25b393861dSkettenis #include <dev/fdt/rsbvar.h> 26b393861dSkettenis 27b393861dSkettenis #include <dev/ofw/openfirm.h> 28b393861dSkettenis #include <dev/ofw/ofw_regulator.h> 29b393861dSkettenis #include <dev/ofw/fdt.h> 30b393861dSkettenis 31de7daf7eSkettenis extern void (*powerdownfn)(void); 32de7daf7eSkettenis 33de7daf7eSkettenis #define AXP209_SDR 0x32 34de7daf7eSkettenis #define AXP209_SDR_SHUTDOWN (1 << 7) 35de7daf7eSkettenis #define AXP209_ADC_EN1 0x82 36de7daf7eSkettenis #define AXP209_ADC_EN1_ACIN (3 << 4) 37de7daf7eSkettenis #define AXP209_ADC_EN1_VBUS (3 << 2) 38de7daf7eSkettenis 397a19eddcSkettenis #define AXP803_IRQ1_EN 0x40 407a19eddcSkettenis #define AXP803_IRQ2_EN 0x41 417a19eddcSkettenis #define AXP803_IRQ3_EN 0x42 427a19eddcSkettenis #define AXP803_IRQ4_EN 0x43 437a19eddcSkettenis #define AXP803_IRQ5_EN 0x44 447a19eddcSkettenis #define AXP803_IRQ5_EN_PEK_SHORT (1 << 4) 457a19eddcSkettenis #define AXP803_IRQ6_EN 0x45 467a19eddcSkettenis #define AXP803_IRQ1_STAT 0x48 477a19eddcSkettenis #define AXP803_IRQ2_STAT 0x49 487a19eddcSkettenis #define AXP803_IRQ3_STAT 0x4a 497a19eddcSkettenis #define AXP803_IRQ4_STAT 0x4b 507a19eddcSkettenis #define AXP803_IRQ5_STAT 0x4c 517a19eddcSkettenis #define AXP803_IRQ5_STAT_PEK_SHORT (1 << 4) 527a19eddcSkettenis #define AXP803_IRQ6_STAT 0x4d 53e6b4a485Skettenis #define AXP803_BAT_CAP_WARN 0xe6 54e6b4a485Skettenis #define AXP803_BAT_CAP_WARN_LV1 0xf0 55e6b4a485Skettenis #define AXP803_BAT_CAP_WARN_LV1BASE 5 56e6b4a485Skettenis #define AXP803_BAT_CAP_WARN_LV2 0x0f 57e6b4a485Skettenis 58b393861dSkettenis #define AXP806_REG_ADDR_EXT 0xff 59b393861dSkettenis #define AXP806_REG_ADDR_EXT_MASTER_MODE (0 << 4) 60b393861dSkettenis #define AXP806_REG_ADDR_EXT_SLAVE_MODE (1 << 4) 61b393861dSkettenis 62bad8128fSkettenis /* Regulators for AXP209, AXP221, AXP806 and AXP809. */ 63de7daf7eSkettenis 64b393861dSkettenis struct axppmic_regdata { 65b393861dSkettenis const char *name; 66b393861dSkettenis uint8_t ereg, emask, eval, dval; 67b393861dSkettenis uint8_t vreg, vmask; 68ae0af167Suaa uint32_t base, delta, nsteps; 69ae0af167Suaa uint32_t base2, delta2, nsteps2; 70b393861dSkettenis }; 71b393861dSkettenis 7237c734d3Snaddy const struct axppmic_regdata axp209_regdata[] = { 73de7daf7eSkettenis { "dcdc2", 0x12, (1 << 4), (1 << 4), (0 << 4), 74ae0af167Suaa 0x23, 0x3f, 700000, 25000, 64 }, 75de7daf7eSkettenis { "dcdc3", 0x12, (1 << 1), (1 << 1), (0 << 1), 76ae0af167Suaa 0x27, 0x7f, 700000, 25000, 113 }, 77de7daf7eSkettenis /* LDO1 can't be controlled */ 78de7daf7eSkettenis { "ldo2", 0x12, (1 << 2), (1 << 2), (0 << 2), 79ae0af167Suaa 0x28, 0xf0, 1800000, (100000 >> 4), (16 << 4) }, 80de7daf7eSkettenis { "ldo3", 0x12, (1 << 6), (1 << 6), (0 << 6), 81ae0af167Suaa 0x29, 0x7f, 700000, 25000, 113 }, 82de7daf7eSkettenis /* LDO4 voltage levels are complicated */ 83de7daf7eSkettenis { "ldo5", 0x90, 0x07, 0x03, 0x07, 84ae0af167Suaa 0x91, 0xf0, 1800000, (100000 >> 4), (16 << 4) }, 85de7daf7eSkettenis { NULL } 86de7daf7eSkettenis }; 87de7daf7eSkettenis 8837c734d3Snaddy const struct axppmic_regdata axp221_regdata[] = { 89bad8128fSkettenis { "dcdc1", 0x10, (1 << 1), (1 << 1), (0 << 1), 90ae0af167Suaa 0x21, 0x1f, 1600000, 100000, 19 }, 91bad8128fSkettenis { "dcdc2", 0x10, (1 << 2), (1 << 2), (0 << 2), 92ae0af167Suaa 0x22, 0x3f, 600000, 20000, 48 }, 93bad8128fSkettenis { "dcdc3", 0x10, (1 << 3), (1 << 3), (0 << 3), 94ae0af167Suaa 0x23, 0x3f, 600000, 20000, 64 }, 95bad8128fSkettenis { "dcdc4", 0x10, (1 << 4), (1 << 4), (0 << 4), 96ae0af167Suaa 0x24, 0x3f, 600000, 20000, 48 }, 97bad8128fSkettenis { "dcdc5", 0x10, (1 << 5), (1 << 5), (0 << 5), 98ae0af167Suaa 0x25, 0x1f, 1000000, 50000, 32 }, 99bad8128fSkettenis { "dc1sw", 0x12, (1 << 7), (1 << 7), (0 << 7) }, 100bad8128fSkettenis { "dc5ldo", 0x10, (1 << 0), (1 << 0), (0 << 0), 101ae0af167Suaa 0x1c, 0x07, 700000, 100000, 8 }, 102bad8128fSkettenis { "aldo1", 0x10, (1 << 6), (1 << 6), (0 << 6), 103ae0af167Suaa 0x28, 0x1f, 700000, 100000, 27 }, 104bad8128fSkettenis { "aldo2", 0x10, (1 << 7), (1 << 7), (0 << 7), 105ae0af167Suaa 0x29, 0x1f, 700000, 100000, 27 }, 106bad8128fSkettenis { "aldo3", 0x13, (1 << 7), (1 << 7), (0 << 7), 107ae0af167Suaa 0x2a, 0x1f, 700000, 100000, 27 }, 108bad8128fSkettenis { "dldo1", 0x12, (1 << 3), (1 << 3), (0 << 3), 109ae0af167Suaa 0x15, 0x1f, 700000, 100000, 27 }, 110bad8128fSkettenis { "dldo2", 0x12, (1 << 4), (1 << 4), (0 << 4), 111ae0af167Suaa 0x16, 0x1f, 700000, 100000, 27 }, 112bad8128fSkettenis { "dldo3", 0x12, (1 << 5), (1 << 5), (0 << 5), 113ae0af167Suaa 0x17, 0x1f, 700000, 100000, 27 }, 114bad8128fSkettenis { "dldo4", 0x12, (1 << 6), (1 << 6), (0 << 6), 115ae0af167Suaa 0x18, 0x1f, 700000, 100000, 27 }, 116bad8128fSkettenis { "eldo1", 0x12, (1 << 0), (1 << 0), (0 << 0), 117ae0af167Suaa 0x19, 0x1f, 700000, 100000, 27 }, 118bad8128fSkettenis { "eldo2", 0x12, (1 << 1), (1 << 1), (0 << 1), 119ae0af167Suaa 0x1a, 0x1f, 700000, 100000, 27 }, 120bad8128fSkettenis { "eldo3", 0x12, (1 << 2), (1 << 2), (0 << 2), 121ae0af167Suaa 0x1b, 0x1f, 700000, 100000, 27 }, 122bad8128fSkettenis { "ldo_io0", 0x90, 0x07, 0x03, 0x04, 123ae0af167Suaa 0x91, 0x1f, 700000, 100000, 27 }, 124bad8128fSkettenis { "ldo_io1", 0x92, 0x07, 0x03, 0x04, 125ae0af167Suaa 0x93, 0x1f, 700000, 100000, 27 }, 126bad8128fSkettenis { NULL } 127bad8128fSkettenis }; 128bad8128fSkettenis 12911ace47bSuaa const struct axppmic_regdata axp313a_regdata[] = { 13011ace47bSuaa /* dcdc1: 1.6-3.4V (100mV step) not supported */ 13111ace47bSuaa { "dcdc1", 0x10, (1 << 0), (1 << 0), (0 << 0), 13211ace47bSuaa 0x13, 0x7f, 500000, 10000, 71, 122000, 20000, 17 }, 13311ace47bSuaa { "dcdc2", 0x10, (1 << 1), (1 << 1), (0 << 1), 13411ace47bSuaa 0x14, 0x7f, 500000, 10000, 71, 122000, 20000, 17 }, 13511ace47bSuaa { "dcdc3", 0x10, (1 << 2), (1 << 2), (0 << 2), 13611ace47bSuaa 0x15, 0x7f, 500000, 10000, 71, 122000, 20000, 32 }, 13711ace47bSuaa { "aldo1", 0x10, (1 << 3), (1 << 3), (0 << 3), 13811ace47bSuaa 0x16, 0x1f, 500000, 100000, 31 }, 13911ace47bSuaa { "dldo1", 0x10, (1 << 4), (1 << 4), (0 << 4), 14011ace47bSuaa 0x17, 0x1f, 500000, 100000, 31 }, 14111ace47bSuaa { NULL } 14211ace47bSuaa }; 14311ace47bSuaa 14437c734d3Snaddy const struct axppmic_regdata axp803_regdata[] = { 145ef258573Skettenis { "dcdc1", 0x10, (1 << 0), (1 << 0), (0 << 0), 146ae0af167Suaa 0x20, 0x1f, 1600000, 100000, 19 }, 147ef258573Skettenis { "dcdc2", 0x10, (1 << 1), (1 << 1), (0 << 1), 148ae0af167Suaa 0x21, 0x7f, 500000, 10000, 71, 1220000, 20000, 5 }, 149ef258573Skettenis { "dcdc3", 0x10, (1 << 2), (1 << 2), (0 << 2), 150ae0af167Suaa 0x22, 0x7f, 500000, 10000, 71, 1220000, 20000, 5 }, 151ef258573Skettenis { "dcdc4", 0x10, (1 << 3), (1 << 3), (0 << 3), 152ae0af167Suaa 0x23, 0x7f, 500000, 10000, 71, 1220000, 20000, 5 }, 153ef258573Skettenis { "dcdc5", 0x10, (1 << 4), (1 << 4), (0 << 4), 154ae0af167Suaa 0x24, 0x7f, 800000, 10000, 33, 1140000, 20000, 36 }, 155ef258573Skettenis { "dcdc6", 0x10, (1 << 5), (1 << 5), (0 << 5), 156ae0af167Suaa 0x25, 0x7f, 600000, 10000, 51, 1120000, 20000, 21 }, 157ef258573Skettenis { "dc1sw", 0x12, (1 << 7), (1 << 7), (0 << 7) }, 158ef258573Skettenis { "aldo1", 0x13, (1 << 5), (1 << 5), (0 << 5), 159ae0af167Suaa 0x28, 0x1f, 700000, 100000, 27 }, 160ef258573Skettenis { "aldo2", 0x13, (1 << 6), (1 << 6), (0 << 6), 161ae0af167Suaa 0x29, 0x1f, 700000, 100000, 27 }, 162ef258573Skettenis { "aldo3", 0x13, (1 << 7), (1 << 7), (0 << 7), 163ae0af167Suaa 0x2a, 0x1f, 700000, 100000, 27 }, 164ef258573Skettenis { "dldo1", 0x12, (1 << 3), (1 << 3), (0 << 3), 165ae0af167Suaa 0x15, 0x1f, 700000, 100000, 27 }, 166ef258573Skettenis { "dldo2", 0x12, (1 << 4), (1 << 4), (0 << 4), 167ae0af167Suaa 0x16, 0x1f, 700000, 100000, 27, 3400000, 200000, 5 }, 168ef258573Skettenis { "dldo3", 0x12, (1 << 5), (1 << 5), (0 << 5), 169ae0af167Suaa 0x17, 0x1f, 700000, 100000, 27 }, 170ef258573Skettenis { "dldo4", 0x12, (1 << 6), (1 << 6), (0 << 6), 171ae0af167Suaa 0x18, 0x1f, 700000, 100000, 27 }, 172ef258573Skettenis { "eldo1", 0x12, (1 << 0), (1 << 0), (0 << 0), 173ae0af167Suaa 0x19, 0x1f, 700000, 50000, 25 }, 174ef258573Skettenis { "eldo2", 0x12, (1 << 1), (1 << 1), (0 << 1), 175ae0af167Suaa 0x1a, 0x1f, 700000, 50000, 25 }, 176ef258573Skettenis { "eldo3", 0x12, (1 << 2), (1 << 2), (0 << 2), 177ae0af167Suaa 0x1b, 0x1f, 700000, 50000, 25 }, 178ef258573Skettenis { "fldo1", 0x13, (1 << 2), (1 << 2), (0 << 2), 179ae0af167Suaa 0x1c, 0x0f, 700000, 50000, 16 }, 180ef258573Skettenis { "fldo2", 0x13, (1 << 3), (1 << 3), (0 << 3), 181ae0af167Suaa 0x1d, 0x0f, 700000, 50000, 16 }, 182ef258573Skettenis { "ldo-io0", 0x90, 0x07, 0x03, 0x04, 183ae0af167Suaa 0x91, 0x1f, 700000, 100000, 27 }, 184ef258573Skettenis { "ldo-io1", 0x92, 0x07, 0x03, 0x04, 185ae0af167Suaa 0x93, 0x1f, 700000, 100000, 27 }, 186ef258573Skettenis { NULL } 187ef258573Skettenis }; 188ef258573Skettenis 18937c734d3Snaddy const struct axppmic_regdata axp806_regdata[] = { 190b393861dSkettenis { "dcdca", 0x10, (1 << 0), (1 << 0), (0 << 0), 191ae0af167Suaa 0x12, 0x7f, 600000, 10000, 51, 1120000, 20000, 21 }, 192b393861dSkettenis { "dcdcb", 0x10, (1 << 1), (1 << 1), (0 << 1), 193ae0af167Suaa 0x13, 0x1f, 1000000, 50000, 32 }, 194b393861dSkettenis { "dcdcc", 0x10, (1 << 2), (1 << 2), (0 << 2), 195ae0af167Suaa 0x14, 0x7f, 600000, 10000, 51, 1120000, 20000, 21 }, 196b393861dSkettenis { "dcdcd", 0x10, (1 << 3), (1 << 3), (0 << 3), 197ae0af167Suaa 0x15, 0x3f, 600000, 20000, 46, 1600000, 100000, 18 }, 198b393861dSkettenis { "dcdce", 0x10, (1 << 4), (1 << 4), (0 << 4), 199ae0af167Suaa 0x16, 0x1f, 1100000, 100000, 24 }, 200b393861dSkettenis { "aldo1", 0x10, (1 << 5), (1 << 5), (0 << 5), 201ae0af167Suaa 0x17, 0x1f, 700000, 100000, 27 }, 202b393861dSkettenis { "aldo2", 0x10, (1 << 6), (1 << 6), (0 << 6), 203ae0af167Suaa 0x18, 0x1f, 700000, 100000, 27 }, 204b393861dSkettenis { "aldo3", 0x10, (1 << 7), (1 << 7), (0 << 7), 205ae0af167Suaa 0x19, 0x1f, 700000, 100000, 27 }, 206b393861dSkettenis { "bldo1", 0x11, (1 << 0), (1 << 0), (0 << 0), 207ae0af167Suaa 0x20, 0x0f, 700000, 100000, 13 }, 208b393861dSkettenis { "bldo2", 0x11, (1 << 1), (1 << 1), (0 << 1), 209ae0af167Suaa 0x21, 0x0f, 700000, 100000, 13 }, 210b393861dSkettenis { "bldo3", 0x11, (1 << 2), (1 << 2), (0 << 2), 211ae0af167Suaa 0x22, 0x0f, 700000, 100000, 13 }, 212b393861dSkettenis { "bldo4", 0x11, (1 << 3), (1 << 3), (0 << 3), 213ae0af167Suaa 0x23, 0x0f, 700000, 100000, 13 }, 214b393861dSkettenis { "cldo1", 0x11, (1 << 4), (1 << 4), (0 << 4), 215ae0af167Suaa 0x24, 0x1f, 700000, 100000 , 27}, 216b393861dSkettenis { "cldo2", 0x11, (1 << 5), (1 << 5), (0 << 5), 217ae0af167Suaa 0x25, 0x1f, 700000, 100000, 28, 3600000, 200000, 4 }, 218b393861dSkettenis { "cldo3", 0x11, (1 << 6), (1 << 6), (0 << 6), 219ae0af167Suaa 0x26, 0x1f, 700000, 100000, 27 }, 220b393861dSkettenis { "sw", 0x11, (1 << 7), (1 << 7), (0 << 7) }, 221b393861dSkettenis { NULL } 222b393861dSkettenis }; 223b393861dSkettenis 22437c734d3Snaddy const struct axppmic_regdata axp809_regdata[] = { 225b393861dSkettenis { "dcdc1", 0x10, (1 << 1), (1 << 1), (0 << 1), 226ae0af167Suaa 0x21, 0x1f, 1600000, 100000, 19 }, 227b393861dSkettenis { "dcdc2", 0x10, (1 << 2), (1 << 2), (0 << 2), 228ae0af167Suaa 0x22, 0x3f, 600000, 20000, 48 }, 229b393861dSkettenis { "dcdc3", 0x10, (1 << 3), (1 << 3), (0 << 3), 230ae0af167Suaa 0x23, 0x3f, 600000, 20000, 64 }, 231b393861dSkettenis { "dcdc4", 0x10, (1 << 4), (1 << 4), (0 << 4), 232ae0af167Suaa 0x24, 0x3f, 600000, 20000, 48, 1800000, 100000, 9 }, 233b393861dSkettenis { "dcdc5", 0x10, (1 << 5), (1 << 5), (0 << 5), 234ae0af167Suaa 0x25, 0x1f, 1000000, 50000, 32 }, 235b393861dSkettenis { "dc5ldo", 0x10, (1 << 0), (1 << 0), (0 << 0), 236ae0af167Suaa 0x1c, 0x07, 700000, 100000, 8 }, 237b393861dSkettenis { "aldo1", 0x10, (1 << 6), (1 << 6), (0 << 6), 238ae0af167Suaa 0x28, 0x1f, 700000, 100000, 27 }, 239b393861dSkettenis { "aldo2", 0x10, (1 << 7), (1 << 7), (0 << 7), 240ae0af167Suaa 0x29, 0x1f, 700000, 100000, 27 }, 241b393861dSkettenis { "aldo3", 0x12, (1 << 5), (1 << 5), (0 << 5), 242ae0af167Suaa 0x2a, 0x1f, 700000, 100000, 27 }, 243b393861dSkettenis { "dldo1", 0x12, (1 << 3), (1 << 3), (0 << 3), 244ae0af167Suaa 0x15, 0x1f, 700000, 100000, 27, 3400000, 200000, 5 }, 245b393861dSkettenis { "dldo2", 0x12, (1 << 4), (1 << 4), (0 << 4), 246ae0af167Suaa 0x16, 0x1f, 700000, 100000, 27 }, 247b393861dSkettenis { "eldo1", 0x12, (1 << 0), (1 << 0), (0 << 0), 248ae0af167Suaa 0x19, 0x1f, 700000, 100000, 27 }, 249b393861dSkettenis { "eldo2", 0x12, (1 << 1), (1 << 1), (0 << 1), 250ae0af167Suaa 0x1a, 0x1f, 700000, 100000, 27 }, 251b393861dSkettenis { "eldo3", 0x12, (1 << 2), (1 << 2), (0 << 2), 252ae0af167Suaa 0x1b, 0x1f, 700000, 100000, 27 }, 253b393861dSkettenis { "ldo_io0", 0x90, 0x07, 0x03, 0x04, 254ae0af167Suaa 0x91, 0x1f, 700000, 100000, 27 }, 255b393861dSkettenis { "ldo_io1", 0x92, 0x07, 0x03, 0x04, 256ae0af167Suaa 0x93, 0x1f, 700000, 100000, 27 }, 257b393861dSkettenis { NULL } 258b393861dSkettenis }; 259b393861dSkettenis 260977d3b0bSkettenis const struct axppmic_regdata axp15060_regdata[] = { 261977d3b0bSkettenis { "dcdc1", 0x10, (1 << 0), (1 << 0), (0 << 0), 262977d3b0bSkettenis 0x13, 0x1f, 15000000, 100000, 20 }, 263977d3b0bSkettenis { "dcdc2", 0x10, (1 << 1), (1 << 1), (0 << 1), 264977d3b0bSkettenis 0x14, 0x7f, 500000, 10000, 71, 1220000, 20000, 17 }, 265977d3b0bSkettenis { "dcdc3", 0x10, (1 << 2), (1 << 2), (0 << 2), 266977d3b0bSkettenis 0x15, 0x7f, 500000, 10000, 71, 1220000, 20000, 17 }, 267977d3b0bSkettenis { "dcdc4", 0x10, (1 << 3), (1 << 3), (0 << 3), 268977d3b0bSkettenis 0x16, 0x7f, 500000, 10000, 71, 1220000, 20000, 17 }, 269977d3b0bSkettenis { "dcdc5", 0x10, (1 << 4), (1 << 4), (0 << 4), 270977d3b0bSkettenis 0x17, 0x7f, 800000, 10000, 33, 1140000, 20000, 36 }, 271977d3b0bSkettenis { "dcdc6", 0x10, (1 << 5), (1 << 5), (0 << 5), 272977d3b0bSkettenis 0x18, 0x1f, 500000, 100000, 30 }, 273977d3b0bSkettenis { "aldo1", 0x11, (1 << 0), (1 << 0), (0 << 0), 274977d3b0bSkettenis 0x19, 0x1f, 700000, 100000, 27 }, 275977d3b0bSkettenis { "aldo2", 0x11, (1 << 1), (1 << 1), (0 << 1), 276977d3b0bSkettenis 0x20, 0x1f, 700000, 100000, 27 }, 277977d3b0bSkettenis { "aldo3", 0x11, (1 << 2), (1 << 2), (0 << 2), 278977d3b0bSkettenis 0x21, 0x1f, 700000, 100000, 27 }, 279977d3b0bSkettenis { "aldo4", 0x11, (1 << 3), (1 << 3), (0 << 3), 280977d3b0bSkettenis 0x22, 0x1f, 700000, 100000, 27 }, 281977d3b0bSkettenis { "aldo5", 0x11, (1 << 4), (1 << 4), (0 << 4), 282977d3b0bSkettenis 0x23, 0x1f, 700000, 100000, 27 }, 283977d3b0bSkettenis { "bldo1", 0x11, (1 << 5), (1 << 5), (0 << 5), 284977d3b0bSkettenis 0x24, 0x1f, 700000, 100000, 27 }, 285977d3b0bSkettenis { "bldo2", 0x11, (1 << 6), (1 << 6), (0 << 6), 286977d3b0bSkettenis 0x25, 0x1f, 700000, 100000, 27 }, 287977d3b0bSkettenis { "bldo3", 0x11, (1 << 7), (1 << 7), (0 << 7), 288977d3b0bSkettenis 0x26, 0x1f, 700000, 100000, 27 }, 289977d3b0bSkettenis { "bldo4", 0x12, (1 << 0), (1 << 0), (0 << 0), 290977d3b0bSkettenis 0x27, 0x1f, 700000, 100000, 27 }, 291977d3b0bSkettenis { "bldo5", 0x12, (1 << 1), (1 << 1), (0 << 1), 292977d3b0bSkettenis 0x28, 0x1f, 700000, 100000, 27 }, 293977d3b0bSkettenis { "cldo1", 0x12, (1 << 2), (1 << 2), (0 << 2), 294977d3b0bSkettenis 0x29, 0x1f, 700000, 100000, 27 }, 295977d3b0bSkettenis { "cldo2", 0x12, (1 << 3), (1 << 3), (0 << 3), 296977d3b0bSkettenis 0x2a, 0x1f, 700000, 100000, 27 }, 297977d3b0bSkettenis { "cldo3", 0x12, (1 << 4), (1 << 4), (0 << 4), 298977d3b0bSkettenis 0x2b, 0x1f, 700000, 100000, 27 }, 299977d3b0bSkettenis { "cldo4", 0x12, (1 << 5), (1 << 5), (0 << 5), 300977d3b0bSkettenis 0x2d, 0x3f, 700000, 100000, 36 }, 301977d3b0bSkettenis { "cpusldo", 0x12, (1 << 6), (1 << 6), (0 << 6), 302977d3b0bSkettenis 0x2e, 0x0f, 700000, 50000, 15 }, 303977d3b0bSkettenis { "sw", 0x12, (1 << 7), (1 << 7), (0 << 7) }, 304977d3b0bSkettenis { NULL } 305977d3b0bSkettenis }; 306977d3b0bSkettenis 307bad8128fSkettenis /* Sensors for AXP209 and AXP221/AXP809. */ 308de7daf7eSkettenis 309e6b4a485Skettenis #define AXPPMIC_NSENSORS 12 310de7daf7eSkettenis 311de7daf7eSkettenis struct axppmic_sensdata { 312de7daf7eSkettenis const char *name; 313de7daf7eSkettenis enum sensor_type type; 314de7daf7eSkettenis uint8_t reg; 315de7daf7eSkettenis uint64_t base, delta; 316de7daf7eSkettenis }; 317de7daf7eSkettenis 31837c734d3Snaddy const struct axppmic_sensdata axp209_sensdata[] = { 319de7daf7eSkettenis { "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) }, 320de7daf7eSkettenis { "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) }, 321de7daf7eSkettenis { "ACIN", SENSOR_VOLTS_DC, 0x56, 0, 1700 }, 322de7daf7eSkettenis { "ACIN", SENSOR_AMPS, 0x58, 0, 625 }, 323de7daf7eSkettenis { "VBUS", SENSOR_VOLTS_DC, 0x5a, 0, 1700 }, 324de7daf7eSkettenis { "VBUS", SENSOR_AMPS, 0x5c, 0, 375 }, 325de7daf7eSkettenis { "", SENSOR_TEMP, 0x5e, 128450000, 100000 }, 326de7daf7eSkettenis { "APS", SENSOR_VOLTS_DC, 0x7e, 0, 1400 }, 327de7daf7eSkettenis { NULL } 328de7daf7eSkettenis }; 329de7daf7eSkettenis 33037c734d3Snaddy const struct axppmic_sensdata axp221_sensdata[] = { 3313f2b37c9Skettenis { "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) }, 3323f2b37c9Skettenis { "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) }, 3333f2b37c9Skettenis { "", SENSOR_TEMP, 0x56, 5450000, 105861 }, 3343f2b37c9Skettenis { NULL } 3353f2b37c9Skettenis }; 3363f2b37c9Skettenis 33737c734d3Snaddy const struct axppmic_sensdata axp803_sensdata[] = { 338ef258573Skettenis { "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) }, 339ef258573Skettenis { "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) }, 340ef258573Skettenis { "", SENSOR_TEMP, 0x56, 5450000, 106250 }, 341ef258573Skettenis { NULL } 342ef258573Skettenis }; 343ef258573Skettenis 34437c734d3Snaddy const struct axppmic_sensdata axp803_battery_sensdata[] = { 345e6b4a485Skettenis { "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) }, 346e6b4a485Skettenis { "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) }, 347e6b4a485Skettenis { "", SENSOR_TEMP, 0x56, 5450000, 106250 }, 348e6b4a485Skettenis { "battery present", SENSOR_INDICATOR, 0x01, (1 << 5), (1 << 4) }, 349e6b4a485Skettenis { "battery charging", SENSOR_INDICATOR, 0x01, (1 << 6), (1 << 6) }, 350e6b4a485Skettenis { "battery percent", SENSOR_PERCENT, 0xb9, 0x7f, (1 << 7) }, 351e6b4a485Skettenis { "battery voltage", SENSOR_VOLTS_DC, 0x78, 0x00, 1100 }, 352e6b4a485Skettenis { "battery charging current", SENSOR_AMPS, 0x7a, 0x00, 1000 }, 353e6b4a485Skettenis { "battery discharging current", SENSOR_AMPS, 0x7c, 0x00, 1000 }, 354e6b4a485Skettenis { "battery maximum capacity", SENSOR_AMPHOUR, 0xe0, 0x00, 1456 }, 355e6b4a485Skettenis { "battery current capacity", SENSOR_AMPHOUR, 0xe2, 0x00, 1456 }, 356e6b4a485Skettenis { NULL } 357e6b4a485Skettenis }; 358e6b4a485Skettenis 359b393861dSkettenis struct axppmic_device { 360b393861dSkettenis const char *name; 361b393861dSkettenis const char *chip; 36237c734d3Snaddy const struct axppmic_regdata *regdata; 36337c734d3Snaddy const struct axppmic_sensdata *sensdata; 364b393861dSkettenis }; 365b393861dSkettenis 36637c734d3Snaddy const struct axppmic_device axppmic_devices[] = { 367de7daf7eSkettenis { "x-powers,axp152", "AXP152" }, 368de7daf7eSkettenis { "x-powers,axp209", "AXP209", axp209_regdata, axp209_sensdata }, 369bad8128fSkettenis { "x-powers,axp221", "AXP221", axp221_regdata, axp221_sensdata }, 370bad8128fSkettenis { "x-powers,axp223", "AXP223", axp221_regdata, axp221_sensdata }, 371ae0af167Suaa { "x-powers,axp305", "AXP305", axp806_regdata }, 37211ace47bSuaa { "x-powers,axp313a", "AXP313A", axp313a_regdata }, 373ef258573Skettenis { "x-powers,axp803", "AXP803", axp803_regdata, axp803_sensdata }, 374830dc0cdSuaa { "x-powers,axp805", "AXP805", axp806_regdata }, 375b393861dSkettenis { "x-powers,axp806", "AXP806", axp806_regdata }, 376977d3b0bSkettenis { "x-powers,axp809", "AXP809", axp809_regdata, axp221_sensdata }, 377977d3b0bSkettenis { "x-powers,axp15060", "AXP15060", axp15060_regdata }, 378b393861dSkettenis }; 379b393861dSkettenis 380b393861dSkettenis const struct axppmic_device * 381b393861dSkettenis axppmic_lookup(const char *name) 382b393861dSkettenis { 383b393861dSkettenis int i; 384b393861dSkettenis 385b393861dSkettenis for (i = 0; i < nitems(axppmic_devices); i++) { 386b393861dSkettenis if (strcmp(name, axppmic_devices[i].name) == 0) 387b393861dSkettenis return &axppmic_devices[i]; 388b393861dSkettenis } 389b393861dSkettenis 390b393861dSkettenis return NULL; 391b393861dSkettenis } 392b393861dSkettenis 393b393861dSkettenis struct axppmic_softc { 394b393861dSkettenis struct device sc_dev; 395b393861dSkettenis void *sc_cookie; 396de7daf7eSkettenis uint16_t sc_addr; 3977a19eddcSkettenis const char *sc_name; 398b393861dSkettenis 399de7daf7eSkettenis uint8_t (*sc_read)(struct axppmic_softc *, uint8_t); 400de7daf7eSkettenis void (*sc_write)(struct axppmic_softc *, uint8_t, uint8_t); 40137c734d3Snaddy const struct axppmic_regdata *sc_regdata; 40237c734d3Snaddy const struct axppmic_sensdata *sc_sensdata; 403de7daf7eSkettenis 404de7daf7eSkettenis struct ksensor sc_sensor[AXPPMIC_NSENSORS]; 405de7daf7eSkettenis struct ksensordev sc_sensordev; 406e6b4a485Skettenis 407e6b4a485Skettenis uint8_t sc_warn; 408e6b4a485Skettenis uint8_t sc_crit; 409b393861dSkettenis }; 410b393861dSkettenis 41130025dadSpatrick static inline uint8_t 412b393861dSkettenis axppmic_read_reg(struct axppmic_softc *sc, uint8_t reg) 413b393861dSkettenis { 414de7daf7eSkettenis return sc->sc_read(sc, reg); 415b393861dSkettenis } 416b393861dSkettenis 41730025dadSpatrick static inline void 418b393861dSkettenis axppmic_write_reg(struct axppmic_softc *sc, uint8_t reg, uint8_t value) 419b393861dSkettenis { 420de7daf7eSkettenis sc->sc_write(sc, reg, value); 421b393861dSkettenis } 422b393861dSkettenis 423de7daf7eSkettenis void axppmic_attach_common(struct axppmic_softc *, const char *, int); 4247a19eddcSkettenis int axppmic_activate(struct device *, int); 425de7daf7eSkettenis 426de7daf7eSkettenis /* I2C interface */ 427de7daf7eSkettenis 428de7daf7eSkettenis int axppmic_i2c_match(struct device *, void *, void *); 429de7daf7eSkettenis void axppmic_i2c_attach(struct device *, struct device *, void *); 430de7daf7eSkettenis 4319fdf0c62Smpi const struct cfattach axppmic_ca = { 4327a19eddcSkettenis sizeof(struct axppmic_softc), axppmic_i2c_match, axppmic_i2c_attach, 4337a19eddcSkettenis NULL, axppmic_activate 434de7daf7eSkettenis }; 435de7daf7eSkettenis 436de7daf7eSkettenis struct cfdriver axppmic_cd = { 437de7daf7eSkettenis NULL, "axppmic", DV_DULL 438de7daf7eSkettenis }; 439de7daf7eSkettenis 440de7daf7eSkettenis uint8_t axppmic_i2c_read(struct axppmic_softc *, uint8_t); 441de7daf7eSkettenis void axppmic_i2c_write(struct axppmic_softc *, uint8_t, uint8_t); 442de7daf7eSkettenis 443de7daf7eSkettenis int 444de7daf7eSkettenis axppmic_i2c_match(struct device *parent, void *match, void *aux) 445de7daf7eSkettenis { 446de7daf7eSkettenis struct i2c_attach_args *ia = aux; 447de7daf7eSkettenis 448de7daf7eSkettenis if (axppmic_lookup(ia->ia_name)) 449de7daf7eSkettenis return 1; 450de7daf7eSkettenis return 0; 451de7daf7eSkettenis } 452de7daf7eSkettenis 453de7daf7eSkettenis void 454de7daf7eSkettenis axppmic_i2c_attach(struct device *parent, struct device *self, void *aux) 455de7daf7eSkettenis { 456de7daf7eSkettenis struct axppmic_softc *sc = (struct axppmic_softc *)self; 457de7daf7eSkettenis struct i2c_attach_args *ia = aux; 458de7daf7eSkettenis int node = *(int *)ia->ia_cookie; 459de7daf7eSkettenis 460de7daf7eSkettenis sc->sc_cookie = ia->ia_tag; 461de7daf7eSkettenis sc->sc_addr = ia->ia_addr; 462de7daf7eSkettenis sc->sc_read = axppmic_i2c_read; 463de7daf7eSkettenis sc->sc_write = axppmic_i2c_write; 464de7daf7eSkettenis 465de7daf7eSkettenis axppmic_attach_common(sc, ia->ia_name, node); 466de7daf7eSkettenis } 467de7daf7eSkettenis 468de7daf7eSkettenis uint8_t 469de7daf7eSkettenis axppmic_i2c_read(struct axppmic_softc *sc, uint8_t reg) 470de7daf7eSkettenis { 471de7daf7eSkettenis i2c_tag_t tag = sc->sc_cookie; 472de7daf7eSkettenis int flags = cold ? I2C_F_POLL : 0; 473de7daf7eSkettenis int error; 474de7daf7eSkettenis uint8_t value; 475de7daf7eSkettenis 476de7daf7eSkettenis iic_acquire_bus(tag, flags); 477de7daf7eSkettenis error = iic_smbus_read_byte(tag, sc->sc_addr, reg, &value, flags); 478de7daf7eSkettenis iic_release_bus(tag, flags); 479de7daf7eSkettenis if (error) { 480bad8128fSkettenis printf("%s: SMBus read byte from 0x%02x failed\n", 481bad8128fSkettenis sc->sc_dev.dv_xname, reg); 482de7daf7eSkettenis return 0xff; 483de7daf7eSkettenis } 484de7daf7eSkettenis 485de7daf7eSkettenis return value; 486de7daf7eSkettenis } 487de7daf7eSkettenis 488de7daf7eSkettenis void 489de7daf7eSkettenis axppmic_i2c_write(struct axppmic_softc *sc, uint8_t reg, uint8_t value) 490de7daf7eSkettenis { 491de7daf7eSkettenis i2c_tag_t tag = sc->sc_cookie; 492de7daf7eSkettenis int flags = cold ? I2C_F_POLL : 0; 493de7daf7eSkettenis int error; 494de7daf7eSkettenis 495de7daf7eSkettenis iic_acquire_bus(tag, flags); 496de7daf7eSkettenis error = iic_smbus_write_byte(tag, sc->sc_addr, reg, value, flags); 497de7daf7eSkettenis iic_release_bus(tag, flags); 498de7daf7eSkettenis if (error) 499bad8128fSkettenis printf("%s: SMBus write byte to 0x%02x failed\n", 500bad8128fSkettenis sc->sc_dev.dv_xname, reg); 501de7daf7eSkettenis } 502de7daf7eSkettenis 503de7daf7eSkettenis /* RSB interface */ 504de7daf7eSkettenis 505a20bb377Skettenis #include "sxirsb.h" 506a20bb377Skettenis 507a20bb377Skettenis #if NSXIRSB > 0 508a20bb377Skettenis 509de7daf7eSkettenis int axppmic_rsb_match(struct device *, void *, void *); 510de7daf7eSkettenis void axppmic_rsb_attach(struct device *, struct device *, void *); 511b393861dSkettenis 5129fdf0c62Smpi const struct cfattach axppmic_rsb_ca = { 5137a19eddcSkettenis sizeof(struct axppmic_softc), axppmic_rsb_match, axppmic_rsb_attach, 5147a19eddcSkettenis NULL, axppmic_activate 515b393861dSkettenis }; 516b393861dSkettenis 517de7daf7eSkettenis uint8_t axppmic_rsb_read(struct axppmic_softc *, uint8_t); 518de7daf7eSkettenis void axppmic_rsb_write(struct axppmic_softc *, uint8_t, uint8_t); 519b393861dSkettenis 520b393861dSkettenis int 521de7daf7eSkettenis axppmic_rsb_match(struct device *parent, void *match, void *aux) 522b393861dSkettenis { 523b393861dSkettenis struct rsb_attach_args *ra = aux; 524b393861dSkettenis 525b393861dSkettenis if (axppmic_lookup(ra->ra_name)) 526b393861dSkettenis return 1; 527b393861dSkettenis return 0; 528b393861dSkettenis } 529b393861dSkettenis 530b393861dSkettenis void 531de7daf7eSkettenis axppmic_rsb_attach(struct device *parent, struct device *self, void *aux) 532b393861dSkettenis { 533b393861dSkettenis struct axppmic_softc *sc = (struct axppmic_softc *)self; 534b393861dSkettenis struct rsb_attach_args *ra = aux; 535b393861dSkettenis 536b393861dSkettenis sc->sc_cookie = ra->ra_cookie; 537de7daf7eSkettenis sc->sc_addr = ra->ra_rta; 538de7daf7eSkettenis sc->sc_read = axppmic_rsb_read; 539de7daf7eSkettenis sc->sc_write = axppmic_rsb_write; 540b393861dSkettenis 541de7daf7eSkettenis axppmic_attach_common(sc, ra->ra_name, ra->ra_node); 542de7daf7eSkettenis } 543de7daf7eSkettenis 544de7daf7eSkettenis uint8_t 545de7daf7eSkettenis axppmic_rsb_read(struct axppmic_softc *sc, uint8_t reg) 546de7daf7eSkettenis { 547de7daf7eSkettenis return rsb_read_1(sc->sc_cookie, sc->sc_addr, reg); 548de7daf7eSkettenis } 549de7daf7eSkettenis 550de7daf7eSkettenis void 551de7daf7eSkettenis axppmic_rsb_write(struct axppmic_softc *sc, uint8_t reg, uint8_t value) 552de7daf7eSkettenis { 553de7daf7eSkettenis rsb_write_1(sc->sc_cookie, sc->sc_addr, reg, value); 554de7daf7eSkettenis } 555de7daf7eSkettenis 556a20bb377Skettenis #endif 557a20bb377Skettenis 558de7daf7eSkettenis /* Common code */ 559de7daf7eSkettenis 560e6b4a485Skettenis void axppmic_attach_node(struct axppmic_softc *, int); 561de7daf7eSkettenis void axppmic_attach_regulators(struct axppmic_softc *, int); 562de7daf7eSkettenis void axppmic_attach_sensors(struct axppmic_softc *); 563de7daf7eSkettenis 564de7daf7eSkettenis struct axppmic_softc *axppmic_sc; 565de7daf7eSkettenis void axp209_powerdown(void); 566de7daf7eSkettenis 567de7daf7eSkettenis void 568de7daf7eSkettenis axppmic_attach_common(struct axppmic_softc *sc, const char *name, int node) 569de7daf7eSkettenis { 570de7daf7eSkettenis const struct axppmic_device *device; 571e6b4a485Skettenis int child; 572de7daf7eSkettenis 573de7daf7eSkettenis device = axppmic_lookup(name); 574b393861dSkettenis printf(": %s\n", device->chip); 575b393861dSkettenis 5767a19eddcSkettenis sc->sc_name = device->name; 577b393861dSkettenis sc->sc_regdata = device->regdata; 578de7daf7eSkettenis sc->sc_sensdata = device->sensdata; 579b393861dSkettenis 580b393861dSkettenis /* Switch AXP806 into master or slave mode. */ 581ae0af167Suaa if (strcmp(name, "x-powers,axp305") == 0 || 582ae0af167Suaa strcmp(name, "x-powers,axp805") == 0 || 583830dc0cdSuaa strcmp(name, "x-powers,axp806") == 0) { 584830dc0cdSuaa if (OF_getproplen(node, "x-powers,master-mode") == 0 || 585830dc0cdSuaa OF_getproplen(node, "x-powers,self-working-mode") == 0) { 586b393861dSkettenis axppmic_write_reg(sc, AXP806_REG_ADDR_EXT, 587b393861dSkettenis AXP806_REG_ADDR_EXT_MASTER_MODE); 588b393861dSkettenis } else { 589b393861dSkettenis axppmic_write_reg(sc, AXP806_REG_ADDR_EXT, 590b393861dSkettenis AXP806_REG_ADDR_EXT_SLAVE_MODE); 591b393861dSkettenis } 592b393861dSkettenis } 593b393861dSkettenis 5944b1a56afSjsg /* Enable data collection on AXP209. */ 595de7daf7eSkettenis if (strcmp(name, "x-powers,axp209") == 0) { 596de7daf7eSkettenis uint8_t reg; 597de7daf7eSkettenis 598de7daf7eSkettenis /* Turn on sampling of ACIN and VBUS voltage and current. */ 599de7daf7eSkettenis reg = axppmic_read_reg(sc, AXP209_ADC_EN1); 600de7daf7eSkettenis reg |= AXP209_ADC_EN1_ACIN; 601de7daf7eSkettenis reg |= AXP209_ADC_EN1_VBUS; 602de7daf7eSkettenis axppmic_write_reg(sc, AXP209_ADC_EN1, reg); 603b393861dSkettenis } 604b393861dSkettenis 605e6b4a485Skettenis /* Read battery warning levels on AXP803. */ 606e6b4a485Skettenis if (strcmp(name, "x-powers,axp803") == 0) { 607e6b4a485Skettenis uint8_t value; 608e6b4a485Skettenis 609e6b4a485Skettenis value = axppmic_read_reg(sc, AXP803_BAT_CAP_WARN); 610e6b4a485Skettenis sc->sc_warn = ((value & AXP803_BAT_CAP_WARN_LV1) >> 4); 611e6b4a485Skettenis sc->sc_warn += AXP803_BAT_CAP_WARN_LV1BASE; 612e6b4a485Skettenis sc->sc_crit = (value & AXP803_BAT_CAP_WARN_LV2); 613e6b4a485Skettenis } 614e6b4a485Skettenis 615e6b4a485Skettenis for (child = OF_child(node); child; child = OF_peer(child)) 616e6b4a485Skettenis axppmic_attach_node(sc, child); 617e6b4a485Skettenis 618de7daf7eSkettenis if (sc->sc_regdata) 619de7daf7eSkettenis axppmic_attach_regulators(sc, node); 620de7daf7eSkettenis 621de7daf7eSkettenis if (sc->sc_sensdata) 622de7daf7eSkettenis axppmic_attach_sensors(sc); 623de7daf7eSkettenis 6247a19eddcSkettenis /* Disable all interrupts on AXP803. */ 6257a19eddcSkettenis if (strcmp(name, "x-powers,axp803") == 0) { 6267a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ1_EN, 0); 6277a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ2_EN, 0); 6287a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ3_EN, 0); 6297a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ4_EN, 0); 6307a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ5_EN, 0); 6317a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ6_EN, 0); 6327a19eddcSkettenis } 6337a19eddcSkettenis 634de7daf7eSkettenis #ifdef __armv7__ 635de7daf7eSkettenis if (strcmp(name, "x-powers,axp152") == 0 || 636de7daf7eSkettenis strcmp(name, "x-powers,axp209") == 0) { 637de7daf7eSkettenis axppmic_sc = sc; 638de7daf7eSkettenis powerdownfn = axp209_powerdown; 639de7daf7eSkettenis } 640ef258573Skettenis #endif 64117b371d9Skettenis 64217b371d9Skettenis #ifdef SUSPEND 64317b371d9Skettenis /* AXP803 can wake us up. */ 64417b371d9Skettenis if (strcmp(name, "x-powers,axp803") == 0) 64517b371d9Skettenis device_register_wakeup(&sc->sc_dev); 64617b371d9Skettenis #endif 647de7daf7eSkettenis } 648de7daf7eSkettenis 649e6b4a485Skettenis void 650e6b4a485Skettenis axppmic_attach_node(struct axppmic_softc *sc, int node) 651e6b4a485Skettenis { 652e6b4a485Skettenis char status[32]; 653e6b4a485Skettenis 654e6b4a485Skettenis if (OF_getprop(node, "status", status, sizeof(status)) > 0 && 655e6b4a485Skettenis strcmp(status, "disabled") == 0) 656e6b4a485Skettenis return; 657e6b4a485Skettenis 658e6b4a485Skettenis if (OF_is_compatible(node, "x-powers,axp803-battery-power-supply")) 659e6b4a485Skettenis sc->sc_sensdata = axp803_battery_sensdata; 660e6b4a485Skettenis } 661e6b4a485Skettenis 6627a19eddcSkettenis int 6637a19eddcSkettenis axppmic_activate(struct device *self, int act) 6647a19eddcSkettenis { 6657a19eddcSkettenis struct axppmic_softc *sc = (struct axppmic_softc *)self; 6667a19eddcSkettenis 6677a19eddcSkettenis switch (act) { 6687a19eddcSkettenis case DVACT_SUSPEND: 6697a19eddcSkettenis if (strcmp(sc->sc_name, "x-powers,axp803") == 0) { 6707a19eddcSkettenis /* Enable interrupt for short power button press. */ 6717a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ5_STAT, 6727a19eddcSkettenis AXP803_IRQ5_STAT_PEK_SHORT); 6737a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ5_EN, 6747a19eddcSkettenis AXP803_IRQ5_EN_PEK_SHORT); 6757a19eddcSkettenis } 6767a19eddcSkettenis break; 6777a19eddcSkettenis case DVACT_RESUME: 6787a19eddcSkettenis if (strcmp(sc->sc_name, "x-powers,axp803") == 0) { 6797a19eddcSkettenis /* Disable interrupt for short power button press. */ 6807a19eddcSkettenis axppmic_write_reg(sc, AXP803_IRQ5_EN, 0); 6817a19eddcSkettenis } 6827a19eddcSkettenis break; 6837a19eddcSkettenis } 6847a19eddcSkettenis 6857a19eddcSkettenis return 0; 6867a19eddcSkettenis } 6877a19eddcSkettenis 688de7daf7eSkettenis /* Regulators */ 689de7daf7eSkettenis 690b393861dSkettenis struct axppmic_regulator { 691b393861dSkettenis struct axppmic_softc *ar_sc; 692b393861dSkettenis 693b393861dSkettenis uint8_t ar_ereg, ar_emask; 694b393861dSkettenis uint8_t ar_eval, ar_dval; 695b393861dSkettenis 696b393861dSkettenis uint8_t ar_vreg, ar_vmask; 697ae0af167Suaa uint32_t ar_base, ar_delta, ar_nsteps; 698ae0af167Suaa uint32_t ar_base2, ar_delta2, ar_nsteps2; 699b393861dSkettenis 700b393861dSkettenis struct regulator_device ar_rd; 701b393861dSkettenis }; 702b393861dSkettenis 703de7daf7eSkettenis void axppmic_attach_regulator(struct axppmic_softc *, int); 704b393861dSkettenis uint32_t axppmic_get_voltage(void *); 705b393861dSkettenis int axppmic_set_voltage(void *, uint32_t); 706b393861dSkettenis int axppmic_enable(void *, int); 707b393861dSkettenis 708b393861dSkettenis void 709de7daf7eSkettenis axppmic_attach_regulators(struct axppmic_softc *sc, int node) 710de7daf7eSkettenis { 711de7daf7eSkettenis node = OF_getnodebyname(node, "regulators"); 712de7daf7eSkettenis if (node == 0) 713de7daf7eSkettenis return; 714de7daf7eSkettenis 715de7daf7eSkettenis for (node = OF_child(node); node; node = OF_peer(node)) 716de7daf7eSkettenis axppmic_attach_regulator(sc, node); 717de7daf7eSkettenis } 718de7daf7eSkettenis 719de7daf7eSkettenis void 720b393861dSkettenis axppmic_attach_regulator(struct axppmic_softc *sc, int node) 721b393861dSkettenis { 722b393861dSkettenis struct axppmic_regulator *ar; 723b393861dSkettenis char name[32]; 724b393861dSkettenis int i; 725b393861dSkettenis 726b393861dSkettenis name[0] = 0; 727b393861dSkettenis OF_getprop(node, "name", name, sizeof(name)); 728b393861dSkettenis name[sizeof(name) - 1] = 0; 729b393861dSkettenis for (i = 0; sc->sc_regdata[i].name; i++) { 730b393861dSkettenis if (strcmp(sc->sc_regdata[i].name, name) == 0) 731b393861dSkettenis break; 732b393861dSkettenis } 733b393861dSkettenis if (sc->sc_regdata[i].name == NULL) 734b393861dSkettenis return; 735b393861dSkettenis 736b393861dSkettenis ar = malloc(sizeof(*ar), M_DEVBUF, M_WAITOK | M_ZERO); 737b393861dSkettenis ar->ar_sc = sc; 738b393861dSkettenis 739b393861dSkettenis ar->ar_ereg = sc->sc_regdata[i].ereg; 740b393861dSkettenis ar->ar_emask = sc->sc_regdata[i].emask; 741b393861dSkettenis ar->ar_eval = sc->sc_regdata[i].eval; 742b393861dSkettenis ar->ar_dval = sc->sc_regdata[i].dval; 743b393861dSkettenis ar->ar_vreg = sc->sc_regdata[i].vreg; 744b393861dSkettenis ar->ar_vmask = sc->sc_regdata[i].vmask; 745b393861dSkettenis ar->ar_base = sc->sc_regdata[i].base; 746b393861dSkettenis ar->ar_delta = sc->sc_regdata[i].delta; 747ae0af167Suaa ar->ar_nsteps = sc->sc_regdata[i].nsteps; 748ae0af167Suaa ar->ar_base2 = sc->sc_regdata[i].base2; 749ae0af167Suaa ar->ar_delta2 = sc->sc_regdata[i].delta2; 750ae0af167Suaa ar->ar_nsteps2 = sc->sc_regdata[i].nsteps2; 751b393861dSkettenis 752b393861dSkettenis ar->ar_rd.rd_node = node; 753b393861dSkettenis ar->ar_rd.rd_cookie = ar; 754b393861dSkettenis ar->ar_rd.rd_get_voltage = axppmic_get_voltage; 755b393861dSkettenis ar->ar_rd.rd_set_voltage = axppmic_set_voltage; 756b393861dSkettenis ar->ar_rd.rd_enable = axppmic_enable; 757b393861dSkettenis regulator_register(&ar->ar_rd); 758b393861dSkettenis } 759b393861dSkettenis 760b393861dSkettenis uint32_t 761b393861dSkettenis axppmic_get_voltage(void *cookie) 762b393861dSkettenis { 763b393861dSkettenis struct axppmic_regulator *ar = cookie; 764b393861dSkettenis uint32_t voltage; 765b393861dSkettenis uint8_t value; 766b393861dSkettenis 767b393861dSkettenis value = axppmic_read_reg(ar->ar_sc, ar->ar_vreg); 768b393861dSkettenis value &= ar->ar_vmask; 769ae0af167Suaa if (ar->ar_base2 > 0 && value >= ar->ar_nsteps) { 770ae0af167Suaa voltage = 771ae0af167Suaa ar->ar_base2 + (value - ar->ar_nsteps) * ar->ar_delta2; 772ae0af167Suaa } else { 773b393861dSkettenis voltage = ar->ar_base + value * ar->ar_delta; 774b393861dSkettenis } 775b393861dSkettenis return voltage; 776b393861dSkettenis } 777b393861dSkettenis 778b393861dSkettenis int 779b393861dSkettenis axppmic_set_voltage(void *cookie, uint32_t voltage) 780b393861dSkettenis { 781b393861dSkettenis struct axppmic_regulator *ar = cookie; 782b393861dSkettenis uint32_t value, reg; 783b393861dSkettenis 784b393861dSkettenis if (voltage < ar->ar_base) 785b393861dSkettenis return EINVAL; 786ae0af167Suaa if (ar->ar_base2 > 0 && voltage >= ar->ar_base2) { 787ae0af167Suaa value = (voltage - ar->ar_base2) / ar->ar_delta2; 788ae0af167Suaa if (value >= ar->ar_nsteps2) 789ae0af167Suaa return EINVAL; 790ae0af167Suaa value += ar->ar_nsteps; 791ae0af167Suaa } else { 792b393861dSkettenis value = (voltage - ar->ar_base) / ar->ar_delta; 793ae0af167Suaa if (value >= ar->ar_nsteps) 794ae0af167Suaa return EINVAL; 795b393861dSkettenis } 796b393861dSkettenis if (value > ar->ar_vmask) 797b393861dSkettenis return EINVAL; 798b393861dSkettenis 799b393861dSkettenis reg = axppmic_read_reg(ar->ar_sc, ar->ar_vreg); 800ae0af167Suaa axppmic_write_reg(ar->ar_sc, ar->ar_vreg, 801ae0af167Suaa (reg & ~ar->ar_vmask) | (value & ar->ar_vmask)); 802b393861dSkettenis return 0; 803b393861dSkettenis } 804b393861dSkettenis 805b393861dSkettenis int 806b393861dSkettenis axppmic_enable(void *cookie, int on) 807b393861dSkettenis { 808b393861dSkettenis struct axppmic_regulator *ar = cookie; 809b393861dSkettenis uint8_t reg; 810b393861dSkettenis 811b393861dSkettenis reg = axppmic_read_reg(ar->ar_sc, ar->ar_ereg); 812b393861dSkettenis reg &= ~ar->ar_emask; 813b393861dSkettenis if (on) 814b393861dSkettenis reg |= ar->ar_eval; 815b393861dSkettenis else 816b393861dSkettenis reg |= ar->ar_dval; 817b393861dSkettenis axppmic_write_reg(ar->ar_sc, ar->ar_ereg, reg); 818b393861dSkettenis return 0; 819b393861dSkettenis } 820de7daf7eSkettenis 821de7daf7eSkettenis /* Sensors */ 822de7daf7eSkettenis 823de7daf7eSkettenis void axppmic_update_sensors(void *); 824de7daf7eSkettenis void axppmic_update_indicator(struct axppmic_softc *, int); 825e6b4a485Skettenis void axppmic_update_percent(struct axppmic_softc *, int); 826e6b4a485Skettenis void axppmic_update_amphour(struct axppmic_softc *, int); 827de7daf7eSkettenis void axppmic_update_sensor(struct axppmic_softc *, int); 828de7daf7eSkettenis 829de7daf7eSkettenis void 830de7daf7eSkettenis axppmic_attach_sensors(struct axppmic_softc *sc) 831de7daf7eSkettenis { 832de7daf7eSkettenis int i; 833de7daf7eSkettenis 834de7daf7eSkettenis for (i = 0; sc->sc_sensdata[i].name; i++) { 835de7daf7eSkettenis KASSERT(i < AXPPMIC_NSENSORS); 836de7daf7eSkettenis 837de7daf7eSkettenis sc->sc_sensor[i].type = sc->sc_sensdata[i].type; 838de7daf7eSkettenis strlcpy(sc->sc_sensor[i].desc, sc->sc_sensdata[i].name, 839de7daf7eSkettenis sizeof(sc->sc_sensor[i].desc)); 840de7daf7eSkettenis sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 841de7daf7eSkettenis } 842de7daf7eSkettenis 843de7daf7eSkettenis axppmic_update_sensors(sc); 844de7daf7eSkettenis if (sensor_task_register(sc, axppmic_update_sensors, 5) == NULL) { 845de7daf7eSkettenis printf(", unable to register update task\n"); 846de7daf7eSkettenis return; 847de7daf7eSkettenis } 848de7daf7eSkettenis 849de7daf7eSkettenis strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 850de7daf7eSkettenis sizeof(sc->sc_sensordev.xname)); 851de7daf7eSkettenis sensordev_install(&sc->sc_sensordev); 852de7daf7eSkettenis } 853de7daf7eSkettenis 854de7daf7eSkettenis void 855de7daf7eSkettenis axppmic_update_sensors(void *arg) 856de7daf7eSkettenis { 857de7daf7eSkettenis struct axppmic_softc *sc = arg; 858de7daf7eSkettenis int i; 859de7daf7eSkettenis 860de7daf7eSkettenis for (i = 0; sc->sc_sensdata[i].name; i++) { 861e6b4a485Skettenis switch (sc->sc_sensdata[i].type) { 862e6b4a485Skettenis case SENSOR_INDICATOR: 863de7daf7eSkettenis axppmic_update_indicator(sc, i); 864e6b4a485Skettenis break; 865e6b4a485Skettenis case SENSOR_PERCENT: 866e6b4a485Skettenis axppmic_update_percent(sc, i); 867e6b4a485Skettenis break; 868e6b4a485Skettenis case SENSOR_AMPHOUR: 869a7aa1e79Skettenis axppmic_update_amphour(sc, i); 870e6b4a485Skettenis break; 871e6b4a485Skettenis default: 872de7daf7eSkettenis axppmic_update_sensor(sc, i); 873e6b4a485Skettenis break; 874e6b4a485Skettenis } 875de7daf7eSkettenis } 876de7daf7eSkettenis } 877de7daf7eSkettenis 878de7daf7eSkettenis void 879de7daf7eSkettenis axppmic_update_indicator(struct axppmic_softc *sc, int i) 880de7daf7eSkettenis { 881de7daf7eSkettenis uint8_t reg = sc->sc_sensdata[i].reg; 882de7daf7eSkettenis uint8_t mask = sc->sc_sensdata[i].base; 883de7daf7eSkettenis uint8_t mask_ok = sc->sc_sensdata[i].delta; 884de7daf7eSkettenis uint8_t value; 885de7daf7eSkettenis 886de7daf7eSkettenis value = axppmic_read_reg(sc, reg); 887de7daf7eSkettenis sc->sc_sensor[i].value = (value & mask) ? 1 : 0; 888de7daf7eSkettenis if (value & mask) { 889de7daf7eSkettenis sc->sc_sensor[i].status = 890de7daf7eSkettenis (value & mask_ok) ? SENSOR_S_OK : SENSOR_S_WARN; 891de7daf7eSkettenis } else { 892de7daf7eSkettenis sc->sc_sensor[i].status = SENSOR_S_UNSPEC; 893de7daf7eSkettenis } 894de7daf7eSkettenis } 895de7daf7eSkettenis 896de7daf7eSkettenis void 897e6b4a485Skettenis axppmic_update_percent(struct axppmic_softc *sc, int i) 898e6b4a485Skettenis { 899e6b4a485Skettenis uint8_t reg = sc->sc_sensdata[i].reg; 900e6b4a485Skettenis uint8_t mask = sc->sc_sensdata[i].base; 901e6b4a485Skettenis uint8_t mask_ok = sc->sc_sensdata[i].delta; 902e6b4a485Skettenis uint8_t value; 903e6b4a485Skettenis 904e6b4a485Skettenis value = axppmic_read_reg(sc, reg); 905e6b4a485Skettenis sc->sc_sensor[i].value = (value & mask) * 1000; 906e6b4a485Skettenis 907e6b4a485Skettenis if (value & mask_ok) { 908e6b4a485Skettenis if ((value & mask) <= sc->sc_crit) 909e6b4a485Skettenis sc->sc_sensor[i].status = SENSOR_S_CRIT; 910e6b4a485Skettenis else if ((value & mask) <= sc->sc_warn) 911e6b4a485Skettenis sc->sc_sensor[i].status = SENSOR_S_WARN; 912e6b4a485Skettenis else 913e6b4a485Skettenis sc->sc_sensor[i].status = SENSOR_S_OK; 914e6b4a485Skettenis } else { 915e6b4a485Skettenis sc->sc_sensor[i].status = SENSOR_S_UNSPEC; 916e6b4a485Skettenis } 917e6b4a485Skettenis } 918e6b4a485Skettenis 919e6b4a485Skettenis void 920e6b4a485Skettenis axppmic_update_amphour(struct axppmic_softc *sc, int i) 921e6b4a485Skettenis { 922e6b4a485Skettenis uint8_t reg = sc->sc_sensdata[i].reg; 923e6b4a485Skettenis uint64_t base = sc->sc_sensdata[i].base; 924e6b4a485Skettenis uint64_t delta = sc->sc_sensdata[i].delta; 925e6b4a485Skettenis uint16_t value; 926e6b4a485Skettenis 927e6b4a485Skettenis value = axppmic_read_reg(sc, reg); 928e6b4a485Skettenis sc->sc_sensor[i].status = (value & 0x80) ? SENSOR_S_OK : SENSOR_S_WARN; 929e6b4a485Skettenis value = ((value & 0x7f) << 8) | axppmic_read_reg(sc, reg + 1); 930e6b4a485Skettenis sc->sc_sensor[i].value = base + value * delta; 931e6b4a485Skettenis } 932e6b4a485Skettenis 933e6b4a485Skettenis void 934de7daf7eSkettenis axppmic_update_sensor(struct axppmic_softc *sc, int i) 935de7daf7eSkettenis { 936de7daf7eSkettenis uint8_t reg = sc->sc_sensdata[i].reg; 937de7daf7eSkettenis uint64_t base = sc->sc_sensdata[i].base; 938de7daf7eSkettenis uint64_t delta = sc->sc_sensdata[i].delta; 939de7daf7eSkettenis uint16_t value; 940de7daf7eSkettenis 941de7daf7eSkettenis value = axppmic_read_reg(sc, reg); 942de7daf7eSkettenis value = (value << 4) | axppmic_read_reg(sc, reg + 1); 943de7daf7eSkettenis sc->sc_sensor[i].value = base + value * delta; 944de7daf7eSkettenis } 945de7daf7eSkettenis 946de7daf7eSkettenis void 947de7daf7eSkettenis axp209_powerdown(void) 948de7daf7eSkettenis { 949de7daf7eSkettenis axppmic_write_reg(axppmic_sc, AXP209_SDR, AXP209_SDR_SHUTDOWN); 950de7daf7eSkettenis } 951