12ff143afSAndrew Turner /*- 22ff143afSAndrew Turner * Copyright (c) 2015 Emmanuel Vadot <manu@bidouilliste.com> 32ff143afSAndrew Turner * All rights reserved. 42ff143afSAndrew Turner * 52ff143afSAndrew Turner * Redistribution and use in source and binary forms, with or without 62ff143afSAndrew Turner * modification, are permitted provided that the following conditions 72ff143afSAndrew Turner * are met: 82ff143afSAndrew Turner * 1. Redistributions of source code must retain the above copyright 92ff143afSAndrew Turner * notice, this list of conditions and the following disclaimer. 102ff143afSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 112ff143afSAndrew Turner * notice, this list of conditions and the following disclaimer in the 122ff143afSAndrew Turner * documentation and/or other materials provided with the distribution. 132ff143afSAndrew Turner * 142ff143afSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152ff143afSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162ff143afSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172ff143afSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182ff143afSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192ff143afSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202ff143afSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212ff143afSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222ff143afSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232ff143afSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242ff143afSAndrew Turner * SUCH DAMAGE. 252ff143afSAndrew Turner */ 262ff143afSAndrew Turner 272ff143afSAndrew Turner #include <sys/cdefs.h> 282ff143afSAndrew Turner __FBSDID("$FreeBSD$"); 292ff143afSAndrew Turner /* 302ff143afSAndrew Turner * X-Power AXP209 PMU for Allwinner SoCs 312ff143afSAndrew Turner */ 322ff143afSAndrew Turner #include <sys/param.h> 332ff143afSAndrew Turner #include <sys/systm.h> 342ff143afSAndrew Turner #include <sys/eventhandler.h> 352ff143afSAndrew Turner #include <sys/kernel.h> 362ff143afSAndrew Turner #include <sys/module.h> 372ff143afSAndrew Turner #include <sys/clock.h> 382ff143afSAndrew Turner #include <sys/time.h> 392ff143afSAndrew Turner #include <sys/bus.h> 402ff143afSAndrew Turner #include <sys/proc.h> 412ff143afSAndrew Turner #include <sys/reboot.h> 422ff143afSAndrew Turner #include <sys/resource.h> 432ff143afSAndrew Turner #include <sys/rman.h> 442ff143afSAndrew Turner 452ff143afSAndrew Turner #include <dev/iicbus/iicbus.h> 462ff143afSAndrew Turner #include <dev/iicbus/iiconf.h> 472ff143afSAndrew Turner 482ff143afSAndrew Turner #include <dev/ofw/openfirm.h> 492ff143afSAndrew Turner #include <dev/ofw/ofw_bus.h> 502ff143afSAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 512ff143afSAndrew Turner 522ff143afSAndrew Turner #include "iicbus_if.h" 532ff143afSAndrew Turner 542ff143afSAndrew Turner /* Power State Register */ 552ff143afSAndrew Turner #define AXP209_PSR 0x00 562ff143afSAndrew Turner #define AXP209_PSR_ACIN 0x80 572ff143afSAndrew Turner #define AXP209_PSR_VBUS 0x20 582ff143afSAndrew Turner 592ff143afSAndrew Turner /* Shutdown and battery control */ 602ff143afSAndrew Turner #define AXP209_SHUTBAT 0x32 612ff143afSAndrew Turner #define AXP209_SHUTBAT_SHUTDOWN 0x80 622ff143afSAndrew Turner 632ff143afSAndrew Turner struct axp209_softc { 642ff143afSAndrew Turner uint32_t addr; 652ff143afSAndrew Turner struct intr_config_hook enum_hook; 662ff143afSAndrew Turner }; 672ff143afSAndrew Turner 682ff143afSAndrew Turner static int 692ff143afSAndrew Turner axp209_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) 702ff143afSAndrew Turner { 712ff143afSAndrew Turner struct axp209_softc *sc = device_get_softc(dev); 722ff143afSAndrew Turner struct iic_msg msg[2]; 732ff143afSAndrew Turner 742ff143afSAndrew Turner msg[0].slave = sc->addr; 752ff143afSAndrew Turner msg[0].flags = IIC_M_WR; 762ff143afSAndrew Turner msg[0].len = 1; 772ff143afSAndrew Turner msg[0].buf = ® 782ff143afSAndrew Turner 792ff143afSAndrew Turner msg[1].slave = sc->addr; 802ff143afSAndrew Turner msg[1].flags = IIC_M_RD; 812ff143afSAndrew Turner msg[1].len = size; 822ff143afSAndrew Turner msg[1].buf = data; 832ff143afSAndrew Turner 842ff143afSAndrew Turner return (iicbus_transfer(dev, msg, 2)); 852ff143afSAndrew Turner } 862ff143afSAndrew Turner 872ff143afSAndrew Turner static int 882ff143afSAndrew Turner axp209_write(device_t dev, uint8_t reg, uint8_t data) 892ff143afSAndrew Turner { 902ff143afSAndrew Turner uint8_t buffer[2]; 912ff143afSAndrew Turner struct axp209_softc *sc = device_get_softc(dev); 922ff143afSAndrew Turner struct iic_msg msg; 932ff143afSAndrew Turner 942ff143afSAndrew Turner buffer[0] = reg; 952ff143afSAndrew Turner buffer[1] = data; 962ff143afSAndrew Turner 972ff143afSAndrew Turner msg.slave = sc->addr; 982ff143afSAndrew Turner msg.flags = IIC_M_WR; 992ff143afSAndrew Turner msg.len = 2; 1002ff143afSAndrew Turner msg.buf = buffer; 1012ff143afSAndrew Turner 1022ff143afSAndrew Turner return (iicbus_transfer(dev, &msg, 1)); 1032ff143afSAndrew Turner } 1042ff143afSAndrew Turner 1052ff143afSAndrew Turner static void 1062ff143afSAndrew Turner axp209_shutdown(void *devp, int howto) 1072ff143afSAndrew Turner { 1082ff143afSAndrew Turner device_t dev; 1092ff143afSAndrew Turner 1102ff143afSAndrew Turner if (!(howto & RB_POWEROFF)) 1112ff143afSAndrew Turner return; 1122ff143afSAndrew Turner dev = (device_t)devp; 1132ff143afSAndrew Turner 1142ff143afSAndrew Turner if (bootverbose) 1152ff143afSAndrew Turner device_printf(dev, "Shutdown AXP209\n"); 1162ff143afSAndrew Turner 1172ff143afSAndrew Turner axp209_write(dev, AXP209_SHUTBAT, AXP209_SHUTBAT_SHUTDOWN); 1182ff143afSAndrew Turner } 1192ff143afSAndrew Turner 1202ff143afSAndrew Turner static int 1212ff143afSAndrew Turner axp209_probe(device_t dev) 1222ff143afSAndrew Turner { 1232ff143afSAndrew Turner 1242ff143afSAndrew Turner if (!ofw_bus_status_okay(dev)) 1252ff143afSAndrew Turner return (ENXIO); 1262ff143afSAndrew Turner 1272ff143afSAndrew Turner if (!ofw_bus_is_compatible(dev, "x-powers,axp209")) 1282ff143afSAndrew Turner return (ENXIO); 1292ff143afSAndrew Turner 1302ff143afSAndrew Turner device_set_desc(dev, "X-Power AXP209 Power Management Unit"); 1312ff143afSAndrew Turner 1322ff143afSAndrew Turner return (BUS_PROBE_DEFAULT); 1332ff143afSAndrew Turner } 1342ff143afSAndrew Turner 1352ff143afSAndrew Turner static int 1362ff143afSAndrew Turner axp209_attach(device_t dev) 1372ff143afSAndrew Turner { 1382ff143afSAndrew Turner struct axp209_softc *sc; 1392ff143afSAndrew Turner uint8_t data; 1402ff143afSAndrew Turner uint8_t pwr_src; 1412ff143afSAndrew Turner char pwr_name[4][11] = {"Battery", "AC", "USB", "AC and USB"}; 1422ff143afSAndrew Turner 1432ff143afSAndrew Turner sc = device_get_softc(dev); 1442ff143afSAndrew Turner 1452ff143afSAndrew Turner sc->addr = iicbus_get_addr(dev); 1462ff143afSAndrew Turner 1472ff143afSAndrew Turner /* 1482ff143afSAndrew Turner * Read the Power State register 1492ff143afSAndrew Turner * bit 7 is AC presence, bit 5 is VBUS presence. 1502ff143afSAndrew Turner * If none are set then we are running from battery (obviously). 1512ff143afSAndrew Turner */ 1522ff143afSAndrew Turner axp209_read(dev, AXP209_PSR, &data, 1); 1532ff143afSAndrew Turner pwr_src = ((data & AXP209_PSR_ACIN) >> 7) | 1542ff143afSAndrew Turner ((data & AXP209_PSR_VBUS) >> 4); 1552ff143afSAndrew Turner 1562ff143afSAndrew Turner if (bootverbose) 1572ff143afSAndrew Turner device_printf(dev, "AXP209 Powered by %s\n", 1582ff143afSAndrew Turner pwr_name[pwr_src]); 1592ff143afSAndrew Turner 1602ff143afSAndrew Turner EVENTHANDLER_REGISTER(shutdown_final, axp209_shutdown, dev, 1612ff143afSAndrew Turner SHUTDOWN_PRI_LAST); 1622ff143afSAndrew Turner 1632ff143afSAndrew Turner return (0); 1642ff143afSAndrew Turner } 1652ff143afSAndrew Turner 1662ff143afSAndrew Turner static device_method_t axp209_methods[] = { 1672ff143afSAndrew Turner DEVMETHOD(device_probe, axp209_probe), 1682ff143afSAndrew Turner DEVMETHOD(device_attach, axp209_attach), 1692ff143afSAndrew Turner {0, 0}, 1702ff143afSAndrew Turner }; 1712ff143afSAndrew Turner 1722ff143afSAndrew Turner static driver_t axp209_driver = { 1732ff143afSAndrew Turner "axp209_pmu", 1742ff143afSAndrew Turner axp209_methods, 1752ff143afSAndrew Turner sizeof(struct axp209_softc), 1762ff143afSAndrew Turner }; 1772ff143afSAndrew Turner 1782ff143afSAndrew Turner static devclass_t axp209_devclass; 1792ff143afSAndrew Turner 1802ff143afSAndrew Turner DRIVER_MODULE(axp209, iicbus, axp209_driver, axp209_devclass, 0, 0); 1812ff143afSAndrew Turner MODULE_VERSION(axp209, 1); 1822ff143afSAndrew Turner MODULE_DEPEND(axp209, iicbus, 1, 1, 1); 183