axp209.c revision 295654
1181624Skmacy/*-
2181624Skmacy * Copyright (c) 2015 Emmanuel Vadot <manu@bidouilliste.com>
3181624Skmacy * All rights reserved.
4181624Skmacy *
5181624Skmacy * Redistribution and use in source and binary forms, with or without
6181624Skmacy * modification, are permitted provided that the following conditions
7181624Skmacy * are met:
8181624Skmacy * 1. Redistributions of source code must retain the above copyright
9181624Skmacy *    notice, this list of conditions and the following disclaimer.
10181624Skmacy * 2. Redistributions in binary form must reproduce the above copyright
11181624Skmacy *    notice, this list of conditions and the following disclaimer in the
12181624Skmacy *    documentation and/or other materials provided with the distribution.
13181624Skmacy *
14181624Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15181624Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16181624Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17181624Skmacy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18181624Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19181624Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20181624Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21181624Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22181624Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23181624Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24181624Skmacy * SUCH DAMAGE.
25181624Skmacy */
26181624Skmacy
27186557Skmacy#include <sys/cdefs.h>
28181624Skmacy__FBSDID("$FreeBSD: head/sys/arm/allwinner/axp209.c 295654 2016-02-16 11:03:21Z andrew $");
29181624Skmacy/*
30181624Skmacy* X-Power AXP209 PMU for Allwinner SoCs
31181624Skmacy*/
32186557Skmacy#include <sys/param.h>
33186557Skmacy#include <sys/systm.h>
34181624Skmacy#include <sys/eventhandler.h>
35181624Skmacy#include <sys/kernel.h>
36181624Skmacy#include <sys/module.h>
37181624Skmacy#include <sys/clock.h>
38181624Skmacy#include <sys/time.h>
39181624Skmacy#include <sys/bus.h>
40181624Skmacy#include <sys/proc.h>
41181624Skmacy#include <sys/reboot.h>
42181624Skmacy#include <sys/resource.h>
43181624Skmacy#include <sys/rman.h>
44181624Skmacy
45181624Skmacy#include <dev/iicbus/iicbus.h>
46181624Skmacy#include <dev/iicbus/iiconf.h>
47181624Skmacy
48181624Skmacy#include <dev/ofw/openfirm.h>
49181624Skmacy#include <dev/ofw/ofw_bus.h>
50181624Skmacy#include <dev/ofw/ofw_bus_subr.h>
51181624Skmacy
52181624Skmacy#include "iicbus_if.h"
53181624Skmacy
54181624Skmacy/* Power State Register */
55181624Skmacy#define	AXP209_PSR		0x00
56181624Skmacy#define	AXP209_PSR_ACIN		0x80
57181624Skmacy#define	AXP209_PSR_ACIN_SHIFT	7
58181624Skmacy#define	AXP209_PSR_VBUS		0x20
59181624Skmacy#define	AXP209_PSR_VBUS_SHIFT	5
60181624Skmacy
61181624Skmacy/* Shutdown and battery control */
62181624Skmacy#define	AXP209_SHUTBAT		0x32
63181624Skmacy#define	AXP209_SHUTBAT_SHUTDOWN	0x80
64181624Skmacy
65181624Skmacystruct axp209_softc {
66181624Skmacy	uint32_t		addr;
67181624Skmacy	struct intr_config_hook enum_hook;
68181624Skmacy};
69181624Skmacy
70181624Skmacystatic int
71181624Skmacyaxp209_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
72181624Skmacy{
73181624Skmacy	struct axp209_softc *sc = device_get_softc(dev);
74181624Skmacy	struct iic_msg msg[2];
75181624Skmacy
76181624Skmacy	msg[0].slave = sc->addr;
77181624Skmacy	msg[0].flags = IIC_M_WR;
78181624Skmacy	msg[0].len = 1;
79181624Skmacy	msg[0].buf = &reg;
80181624Skmacy
81181624Skmacy	msg[1].slave = sc->addr;
82181624Skmacy	msg[1].flags = IIC_M_RD;
83181624Skmacy	msg[1].len = size;
84181624Skmacy	msg[1].buf = data;
85181624Skmacy
86181624Skmacy	return (iicbus_transfer(dev, msg, 2));
87181624Skmacy}
88181624Skmacy
89181624Skmacystatic int
90181624Skmacyaxp209_write(device_t dev, uint8_t reg, uint8_t data)
91181624Skmacy{
92181624Skmacy	uint8_t buffer[2];
93181624Skmacy	struct axp209_softc *sc = device_get_softc(dev);
94181624Skmacy	struct iic_msg msg;
95181624Skmacy
96181624Skmacy	buffer[0] = reg;
97181624Skmacy	buffer[1] = data;
98181624Skmacy
99181624Skmacy	msg.slave = sc->addr;
100181624Skmacy	msg.flags = IIC_M_WR;
101181624Skmacy	msg.len = 2;
102181624Skmacy	msg.buf = buffer;
103181624Skmacy
104181624Skmacy	return (iicbus_transfer(dev, &msg, 1));
105181624Skmacy}
106181624Skmacy
107181624Skmacystatic void
108181624Skmacyaxp209_shutdown(void *devp, int howto)
109181624Skmacy{
110181624Skmacy	device_t dev;
111181624Skmacy
112181624Skmacy	if (!(howto & RB_POWEROFF))
113181624Skmacy		return;
114181624Skmacy	dev = (device_t)devp;
115181624Skmacy
116181624Skmacy	if (bootverbose)
117181624Skmacy		device_printf(dev, "Shutdown AXP209\n");
118181624Skmacy
119181624Skmacy	axp209_write(dev, AXP209_SHUTBAT, AXP209_SHUTBAT_SHUTDOWN);
120181624Skmacy}
121181624Skmacy
122181624Skmacystatic int
123181624Skmacyaxp209_probe(device_t dev)
124181624Skmacy{
125181624Skmacy
126181624Skmacy	if (!ofw_bus_status_okay(dev))
127181624Skmacy		return (ENXIO);
128181624Skmacy
129181624Skmacy	if (!ofw_bus_is_compatible(dev, "x-powers,axp209"))
130181624Skmacy		return (ENXIO);
131181624Skmacy
132181624Skmacy	device_set_desc(dev, "X-Power AXP209 Power Management Unit");
133181624Skmacy
134181624Skmacy	return (BUS_PROBE_DEFAULT);
135181624Skmacy}
136181624Skmacy
137181624Skmacystatic int
138181624Skmacyaxp209_attach(device_t dev)
139181624Skmacy{
140181624Skmacy	struct axp209_softc *sc;
141181624Skmacy	const char *pwr_name[] = {"Battery", "AC", "USB", "AC and USB"};
142181624Skmacy	uint8_t data;
143181624Skmacy	uint8_t pwr_src;
144181624Skmacy
145181624Skmacy	sc = device_get_softc(dev);
146181624Skmacy
147181624Skmacy	sc->addr = iicbus_get_addr(dev);
148181624Skmacy
149181624Skmacy	if (bootverbose) {
150181624Skmacy		/*
151181624Skmacy		 * Read the Power State register.
152181624Skmacy		 * Shift the AC presence into bit 0.
153181624Skmacy		 * Shift the Battery presence into bit 1.
154181624Skmacy		 */
155181624Skmacy		axp209_read(dev, AXP209_PSR, &data, 1);
156181624Skmacy		pwr_src = ((data & AXP209_PSR_ACIN) >> AXP209_PSR_ACIN_SHIFT) |
157181624Skmacy		    ((data & AXP209_PSR_VBUS) >> (AXP209_PSR_VBUS_SHIFT - 1));
158181624Skmacy
159181624Skmacy		device_printf(dev, "AXP209 Powered by %s\n",
160181624Skmacy		    pwr_name[pwr_src]);
161181624Skmacy	}
162181624Skmacy
163181624Skmacy	EVENTHANDLER_REGISTER(shutdown_final, axp209_shutdown, dev,
164181624Skmacy	    SHUTDOWN_PRI_LAST);
165181624Skmacy
166181624Skmacy	return (0);
167181624Skmacy}
168181624Skmacy
169181624Skmacystatic device_method_t axp209_methods[] = {
170181624Skmacy	DEVMETHOD(device_probe,		axp209_probe),
171181624Skmacy	DEVMETHOD(device_attach,	axp209_attach),
172181624Skmacy	{0, 0},
173181624Skmacy};
174181624Skmacy
175181624Skmacystatic driver_t axp209_driver = {
176181624Skmacy	"axp209_pmu",
177181624Skmacy	axp209_methods,
178181624Skmacy	sizeof(struct axp209_softc),
179181624Skmacy};
180181624Skmacy
181181624Skmacystatic devclass_t axp209_devclass;
182181624Skmacy
183181624SkmacyDRIVER_MODULE(axp209, iicbus, axp209_driver, axp209_devclass, 0, 0);
184181624SkmacyMODULE_VERSION(axp209, 1);
185181624SkmacyMODULE_DEPEND(axp209, iicbus, 1, 1, 1);
186181624Skmacy