axp209.c revision 295634
1295634Sandrew/*- 2295634Sandrew * Copyright (c) 2015 Emmanuel Vadot <manu@bidouilliste.com> 3295634Sandrew * All rights reserved. 4295634Sandrew * 5295634Sandrew * Redistribution and use in source and binary forms, with or without 6295634Sandrew * modification, are permitted provided that the following conditions 7295634Sandrew * are met: 8295634Sandrew * 1. Redistributions of source code must retain the above copyright 9295634Sandrew * notice, this list of conditions and the following disclaimer. 10295634Sandrew * 2. Redistributions in binary form must reproduce the above copyright 11295634Sandrew * notice, this list of conditions and the following disclaimer in the 12295634Sandrew * documentation and/or other materials provided with the distribution. 13295634Sandrew * 14295634Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15295634Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16295634Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17295634Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18295634Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19295634Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20295634Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21295634Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22295634Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23295634Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24295634Sandrew * SUCH DAMAGE. 25295634Sandrew */ 26295634Sandrew 27295634Sandrew#include <sys/cdefs.h> 28295634Sandrew__FBSDID("$FreeBSD: head/sys/arm/allwinner/axp209.c 295634 2016-02-15 19:31:23Z andrew $"); 29295634Sandrew/* 30295634Sandrew* X-Power AXP209 PMU for Allwinner SoCs 31295634Sandrew*/ 32295634Sandrew#include <sys/param.h> 33295634Sandrew#include <sys/systm.h> 34295634Sandrew#include <sys/eventhandler.h> 35295634Sandrew#include <sys/kernel.h> 36295634Sandrew#include <sys/module.h> 37295634Sandrew#include <sys/clock.h> 38295634Sandrew#include <sys/time.h> 39295634Sandrew#include <sys/bus.h> 40295634Sandrew#include <sys/proc.h> 41295634Sandrew#include <sys/reboot.h> 42295634Sandrew#include <sys/resource.h> 43295634Sandrew#include <sys/rman.h> 44295634Sandrew 45295634Sandrew#include <dev/iicbus/iicbus.h> 46295634Sandrew#include <dev/iicbus/iiconf.h> 47295634Sandrew 48295634Sandrew#include <dev/ofw/openfirm.h> 49295634Sandrew#include <dev/ofw/ofw_bus.h> 50295634Sandrew#include <dev/ofw/ofw_bus_subr.h> 51295634Sandrew 52295634Sandrew#include "iicbus_if.h" 53295634Sandrew 54295634Sandrew/* Power State Register */ 55295634Sandrew#define AXP209_PSR 0x00 56295634Sandrew#define AXP209_PSR_ACIN 0x80 57295634Sandrew#define AXP209_PSR_VBUS 0x20 58295634Sandrew 59295634Sandrew/* Shutdown and battery control */ 60295634Sandrew#define AXP209_SHUTBAT 0x32 61295634Sandrew#define AXP209_SHUTBAT_SHUTDOWN 0x80 62295634Sandrew 63295634Sandrewstruct axp209_softc { 64295634Sandrew uint32_t addr; 65295634Sandrew struct intr_config_hook enum_hook; 66295634Sandrew}; 67295634Sandrew 68295634Sandrewstatic int 69295634Sandrewaxp209_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) 70295634Sandrew{ 71295634Sandrew struct axp209_softc *sc = device_get_softc(dev); 72295634Sandrew struct iic_msg msg[2]; 73295634Sandrew 74295634Sandrew msg[0].slave = sc->addr; 75295634Sandrew msg[0].flags = IIC_M_WR; 76295634Sandrew msg[0].len = 1; 77295634Sandrew msg[0].buf = ® 78295634Sandrew 79295634Sandrew msg[1].slave = sc->addr; 80295634Sandrew msg[1].flags = IIC_M_RD; 81295634Sandrew msg[1].len = size; 82295634Sandrew msg[1].buf = data; 83295634Sandrew 84295634Sandrew return (iicbus_transfer(dev, msg, 2)); 85295634Sandrew} 86295634Sandrew 87295634Sandrewstatic int 88295634Sandrewaxp209_write(device_t dev, uint8_t reg, uint8_t data) 89295634Sandrew{ 90295634Sandrew uint8_t buffer[2]; 91295634Sandrew struct axp209_softc *sc = device_get_softc(dev); 92295634Sandrew struct iic_msg msg; 93295634Sandrew 94295634Sandrew buffer[0] = reg; 95295634Sandrew buffer[1] = data; 96295634Sandrew 97295634Sandrew msg.slave = sc->addr; 98295634Sandrew msg.flags = IIC_M_WR; 99295634Sandrew msg.len = 2; 100295634Sandrew msg.buf = buffer; 101295634Sandrew 102295634Sandrew return (iicbus_transfer(dev, &msg, 1)); 103295634Sandrew} 104295634Sandrew 105295634Sandrewstatic void 106295634Sandrewaxp209_shutdown(void *devp, int howto) 107295634Sandrew{ 108295634Sandrew device_t dev; 109295634Sandrew 110295634Sandrew if (!(howto & RB_POWEROFF)) 111295634Sandrew return; 112295634Sandrew dev = (device_t)devp; 113295634Sandrew 114295634Sandrew if (bootverbose) 115295634Sandrew device_printf(dev, "Shutdown AXP209\n"); 116295634Sandrew 117295634Sandrew axp209_write(dev, AXP209_SHUTBAT, AXP209_SHUTBAT_SHUTDOWN); 118295634Sandrew} 119295634Sandrew 120295634Sandrewstatic int 121295634Sandrewaxp209_probe(device_t dev) 122295634Sandrew{ 123295634Sandrew 124295634Sandrew if (!ofw_bus_status_okay(dev)) 125295634Sandrew return (ENXIO); 126295634Sandrew 127295634Sandrew if (!ofw_bus_is_compatible(dev, "x-powers,axp209")) 128295634Sandrew return (ENXIO); 129295634Sandrew 130295634Sandrew device_set_desc(dev, "X-Power AXP209 Power Management Unit"); 131295634Sandrew 132295634Sandrew return (BUS_PROBE_DEFAULT); 133295634Sandrew} 134295634Sandrew 135295634Sandrewstatic int 136295634Sandrewaxp209_attach(device_t dev) 137295634Sandrew{ 138295634Sandrew struct axp209_softc *sc; 139295634Sandrew uint8_t data; 140295634Sandrew uint8_t pwr_src; 141295634Sandrew char pwr_name[4][11] = {"Battery", "AC", "USB", "AC and USB"}; 142295634Sandrew 143295634Sandrew sc = device_get_softc(dev); 144295634Sandrew 145295634Sandrew sc->addr = iicbus_get_addr(dev); 146295634Sandrew 147295634Sandrew /* 148295634Sandrew * Read the Power State register 149295634Sandrew * bit 7 is AC presence, bit 5 is VBUS presence. 150295634Sandrew * If none are set then we are running from battery (obviously). 151295634Sandrew */ 152295634Sandrew axp209_read(dev, AXP209_PSR, &data, 1); 153295634Sandrew pwr_src = ((data & AXP209_PSR_ACIN) >> 7) | 154295634Sandrew ((data & AXP209_PSR_VBUS) >> 4); 155295634Sandrew 156295634Sandrew if (bootverbose) 157295634Sandrew device_printf(dev, "AXP209 Powered by %s\n", 158295634Sandrew pwr_name[pwr_src]); 159295634Sandrew 160295634Sandrew EVENTHANDLER_REGISTER(shutdown_final, axp209_shutdown, dev, 161295634Sandrew SHUTDOWN_PRI_LAST); 162295634Sandrew 163295634Sandrew return (0); 164295634Sandrew} 165295634Sandrew 166295634Sandrewstatic device_method_t axp209_methods[] = { 167295634Sandrew DEVMETHOD(device_probe, axp209_probe), 168295634Sandrew DEVMETHOD(device_attach, axp209_attach), 169295634Sandrew {0, 0}, 170295634Sandrew}; 171295634Sandrew 172295634Sandrewstatic driver_t axp209_driver = { 173295634Sandrew "axp209_pmu", 174295634Sandrew axp209_methods, 175295634Sandrew sizeof(struct axp209_softc), 176295634Sandrew}; 177295634Sandrew 178295634Sandrewstatic devclass_t axp209_devclass; 179295634Sandrew 180295634SandrewDRIVER_MODULE(axp209, iicbus, axp209_driver, axp209_devclass, 0, 0); 181295634SandrewMODULE_VERSION(axp209, 1); 182295634SandrewMODULE_DEPEND(axp209, iicbus, 1, 1, 1); 183