xref: /netbsd-src/sys/arch/sparc64/dev/tadpmu.c (revision 1dc652ef5a0bffbd0917f95e0797bad8c6fc8efd)
1*1dc652efSthorpej /*/* $NetBSD: tadpmu.c,v 1.6 2023/12/20 05:33:58 thorpej Exp $ */
29877af41Smacallan 
39877af41Smacallan /*-
49877af41Smacallan  * Copyright (c) 2018 Michael Lorenz <macallan@netbsd.org>
59877af41Smacallan  * All rights reserved.
69877af41Smacallan  *
79877af41Smacallan  * Redistribution and use in source and binary forms, with or without
89877af41Smacallan  * modification, are permitted provided that the following conditions
99877af41Smacallan  * are met:
109877af41Smacallan  * 1. Redistributions of source code must retain the above copyright
119877af41Smacallan  *    notice, this list of conditions and the following disclaimer.
129877af41Smacallan  * 2. Redistributions in binary form must reproduce the above copyright
139877af41Smacallan  *    notice, this list of conditions and the following disclaimer in the
149877af41Smacallan  *    documentation and/or other materials provided with the distribution.
159877af41Smacallan  *
169877af41Smacallan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
179877af41Smacallan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
189877af41Smacallan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
199877af41Smacallan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
209877af41Smacallan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
219877af41Smacallan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
229877af41Smacallan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
239877af41Smacallan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
249877af41Smacallan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
259877af41Smacallan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
269877af41Smacallan  * POSSIBILITY OF SUCH DAMAGE.
279877af41Smacallan  */
289877af41Smacallan 
299cd58e6bSjdc /* a driver for the PMU found in Tadpole Viper and SPARCle laptops */
309877af41Smacallan 
31e35ff9bdSmacallan #include "opt_tadpmu.h"
32e35ff9bdSmacallan #ifdef HAVE_TADPMU
339877af41Smacallan #include <sys/param.h>
349877af41Smacallan #include <sys/systm.h>
359877af41Smacallan #include <sys/kernel.h>
369877af41Smacallan #include <sys/device.h>
379e92499dSmacallan #include <sys/proc.h>
389877af41Smacallan #include <sys/bus.h>
399877af41Smacallan #include <sys/intr.h>
409a42a893Smacallan #include <sys/kthread.h>
419a42a893Smacallan #include <sys/mutex.h>
429877af41Smacallan 
439877af41Smacallan #include <dev/sysmon/sysmonvar.h>
449e92499dSmacallan #include <dev/sysmon/sysmon_taskq.h>
459877af41Smacallan 
469877af41Smacallan #include <sparc64/dev/tadpmureg.h>
479877af41Smacallan #include <sparc64/dev/tadpmuvar.h>
489877af41Smacallan 
499e92499dSmacallan #ifdef TADPMU_DEBUG
509e92499dSmacallan #define DPRINTF printf
519e92499dSmacallan #else
529e92499dSmacallan #define DPRINTF while (0) printf
539e92499dSmacallan #endif
549e92499dSmacallan 
559877af41Smacallan static bus_space_tag_t tadpmu_iot;
569877af41Smacallan static bus_space_handle_t tadpmu_hcmd;
579877af41Smacallan static bus_space_handle_t tadpmu_hdata;
589cd58e6bSjdc static struct sysmon_envsys *tadpmu_sens_sme;
599cd58e6bSjdc static struct sysmon_envsys *tadpmu_acad_sme;
609cd58e6bSjdc static struct sysmon_envsys *tadpmu_batt_sme;
619cd58e6bSjdc static envsys_data_t tadpmu_sensors[8];
629e92499dSmacallan static uint8_t idata = 0xff;
639e92499dSmacallan static uint8_t ivalid = 0;
649cd58e6bSjdc static uint8_t ev_data = 0;
659a42a893Smacallan static wchan_t tadpmu, tadpmuev;
669cd58e6bSjdc static struct sysmon_pswitch tadpmu_pbutton, tadpmu_lidswitch, tadpmu_dcpower;
679cd58e6bSjdc static kmutex_t tadpmu_lock, data_lock;
689a42a893Smacallan static lwp_t *tadpmu_thread;
699a42a893Smacallan static int tadpmu_dying = 0;
709877af41Smacallan 
719877af41Smacallan static inline void
tadpmu_cmd(uint8_t d)729877af41Smacallan tadpmu_cmd(uint8_t d)
739877af41Smacallan {
749877af41Smacallan 	bus_space_write_1(tadpmu_iot, tadpmu_hcmd, 0, d);
759877af41Smacallan }
769877af41Smacallan 
779877af41Smacallan static inline void
tadpmu_wdata(uint8_t d)789877af41Smacallan tadpmu_wdata(uint8_t d)
799877af41Smacallan {
809877af41Smacallan 	bus_space_write_1(tadpmu_iot, tadpmu_hdata, 0, d);
819877af41Smacallan }
829877af41Smacallan 
839877af41Smacallan static inline uint8_t
tadpmu_status(void)849877af41Smacallan tadpmu_status(void)
859877af41Smacallan {
869877af41Smacallan 	return bus_space_read_1(tadpmu_iot, tadpmu_hcmd, 0);
879877af41Smacallan }
889877af41Smacallan 
899877af41Smacallan static inline uint8_t
tadpmu_data(void)909877af41Smacallan tadpmu_data(void)
919877af41Smacallan {
929877af41Smacallan 	return bus_space_read_1(tadpmu_iot, tadpmu_hdata, 0);
939877af41Smacallan }
949877af41Smacallan 
959877af41Smacallan static void
tadpmu_flush(void)969877af41Smacallan tadpmu_flush(void)
979877af41Smacallan {
989877af41Smacallan 	volatile uint8_t junk, d;
999877af41Smacallan 	int bail = 0;
1009877af41Smacallan 
1019877af41Smacallan 	d = tadpmu_status();
1029877af41Smacallan 	while (d & STATUS_HAVE_DATA) {
1039877af41Smacallan 		junk = tadpmu_data();
1049877af41Smacallan 		__USE(junk);
1059877af41Smacallan 		delay(10);
1069877af41Smacallan 		bail++;
1079877af41Smacallan 		if (bail > 100) {
1089877af41Smacallan 			printf("%s: timeout waiting for data out to clear %2x\n",
1099877af41Smacallan 			    __func__, d);
1109877af41Smacallan 			break;
1119877af41Smacallan 		}
1129877af41Smacallan 		d = tadpmu_status();
1139877af41Smacallan 	}
1149877af41Smacallan 	bail = 0;
1159877af41Smacallan 	d = tadpmu_status();
1169877af41Smacallan 	while (d & STATUS_SEND_DATA) {
1179877af41Smacallan 		bus_space_write_1(tadpmu_iot, tadpmu_hdata, 0, 0);
1189877af41Smacallan 		delay(10);
1199877af41Smacallan 		bail++;
1209877af41Smacallan 		if (bail > 100) {
1219877af41Smacallan 			printf("%s: timeout waiting for data in to clear %02x\n",
1229877af41Smacallan 			    __func__, d);
1239877af41Smacallan 			break;
1249877af41Smacallan 		}
1259877af41Smacallan 		d = tadpmu_status();
1269877af41Smacallan 	}
1279877af41Smacallan }
1289877af41Smacallan 
1299877af41Smacallan static void
tadpmu_send_cmd(uint8_t cmd)1309877af41Smacallan tadpmu_send_cmd(uint8_t cmd)
1319877af41Smacallan {
1329877af41Smacallan 	int bail = 0;
1339877af41Smacallan 	uint8_t d;
1349877af41Smacallan 
1359e92499dSmacallan 	ivalid = 0;
1369877af41Smacallan 	tadpmu_cmd(cmd);
1379877af41Smacallan 
1389877af41Smacallan 	d = tadpmu_status();
1399877af41Smacallan 	while ((d & STATUS_CMD_IN_PROGRESS) == 0) {
1409877af41Smacallan 		delay(10);
1419877af41Smacallan 		bail++;
1429877af41Smacallan 		if (bail > 100) {
1439877af41Smacallan 			printf("%s: timeout waiting for command to start\n",
1449877af41Smacallan 			    __func__);
1459877af41Smacallan 			break;
1469877af41Smacallan 		}
1479877af41Smacallan 		d = tadpmu_status();
1489877af41Smacallan 	}
1499877af41Smacallan }
1509877af41Smacallan 
1519877af41Smacallan static uint8_t
tadpmu_recv(void)1529877af41Smacallan tadpmu_recv(void)
1539877af41Smacallan {
1549877af41Smacallan 	int bail = 0;
1559877af41Smacallan 	uint8_t d;
1569877af41Smacallan 
1579e92499dSmacallan 	if (cold) {
1589877af41Smacallan 		d = tadpmu_status();
1599877af41Smacallan 		while ((d & STATUS_HAVE_DATA) == 0) {
1609877af41Smacallan 			delay(10);
1619877af41Smacallan 			bail++;
1629877af41Smacallan 			if (bail > 1000) {
1639e92499dSmacallan 				printf("%s: timeout waiting for data %02x\n",
1649e92499dSmacallan 				    __func__, d);
1659877af41Smacallan 				break;
1669877af41Smacallan 			}
1679877af41Smacallan 			d = tadpmu_status();
1689877af41Smacallan 		}
1699877af41Smacallan 		return bus_space_read_1(tadpmu_iot, tadpmu_hdata, 0);
1709e92499dSmacallan 	} else {
1719e92499dSmacallan 		while (ivalid == 0)
1729e92499dSmacallan 			tsleep(tadpmu, 0, "pmucmd", 1);
1739e92499dSmacallan 		return idata;
1749e92499dSmacallan 	}
1759877af41Smacallan }
1769877af41Smacallan 
1779877af41Smacallan static void
tadpmu_send(uint8_t v)1789877af41Smacallan tadpmu_send(uint8_t v)
1799877af41Smacallan {
1809877af41Smacallan 	int bail = 0;
1819877af41Smacallan 	uint8_t d;
1829877af41Smacallan 
1839877af41Smacallan 	d = tadpmu_status();
1849877af41Smacallan 	while ((d & STATUS_SEND_DATA) == 0) {
1859877af41Smacallan 		delay(10);
1869877af41Smacallan 		bail++;
1879877af41Smacallan 		if (bail > 1000) {
1889877af41Smacallan 			printf("%s: timeout waiting for PMU ready %02x\n", __func__, d);
1899877af41Smacallan 			break;
1909877af41Smacallan 		}
1919877af41Smacallan 		d = tadpmu_status();
1929877af41Smacallan 	}
1939877af41Smacallan 
1949877af41Smacallan 	tadpmu_wdata(v);
1959877af41Smacallan 
1969877af41Smacallan 	while ((d & STATUS_SEND_DATA) != 0) {
1979877af41Smacallan 		delay(10);
1989877af41Smacallan 		bail++;
1999877af41Smacallan 		if (bail > 1000) {
2009877af41Smacallan 			printf("%s: timeout waiting for accept data %02x\n", __func__, d);
2019877af41Smacallan 			break;
2029877af41Smacallan 		}
2039877af41Smacallan 		d = tadpmu_status();
2049877af41Smacallan 	}
2059877af41Smacallan }
2069877af41Smacallan 
2079cd58e6bSjdc static uint32_t
tadpmu_battery_capacity(uint8_t gstat)2089cd58e6bSjdc tadpmu_battery_capacity(uint8_t gstat)
2099cd58e6bSjdc {
2109cd58e6bSjdc 	uint8_t res;
2119cd58e6bSjdc 
2129cd58e6bSjdc 	if (gstat == GENSTAT_STATE_BATTERY_FULL) {
2139cd58e6bSjdc 		return ENVSYS_BATTERY_CAPACITY_NORMAL;
2149cd58e6bSjdc 	}
2159cd58e6bSjdc 
2169cd58e6bSjdc 	mutex_enter(&tadpmu_lock);
2179cd58e6bSjdc 	tadpmu_flush();
2189cd58e6bSjdc 	tadpmu_send_cmd(CMD_READ_VBATT);
2199cd58e6bSjdc 	res = tadpmu_recv();
2209cd58e6bSjdc 	mutex_exit(&tadpmu_lock);
2219cd58e6bSjdc 
2229cd58e6bSjdc 	if (gstat & GENSTAT_STATE_BATTERY_DISCHARGE) {
2239cd58e6bSjdc 		if (res < TADPMU_BATT_DIS_CAP_CRIT)
2249cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_CRITICAL;
2259cd58e6bSjdc 		if (res < TADPMU_BATT_DIS_CAP_WARN)
2269cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_WARNING;
2279cd58e6bSjdc 		if (res < TADPMU_BATT_DIS_CAP_LOW)
2289cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_LOW;
2299cd58e6bSjdc 		else
2309cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_NORMAL;
2319cd58e6bSjdc 	} else if (gstat == GENSTAT_STATE_BATTERY_CHARGE) {
2329cd58e6bSjdc 		if (res < TADPMU_BATT_CHG_CAP_CRIT)
2339cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_CRITICAL;
2349cd58e6bSjdc 		else if (res < TADPMU_BATT_CHG_CAP_WARN)
2359cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_WARNING;
2369cd58e6bSjdc 		else if (res < TADPMU_BATT_CHG_CAP_LOW)
2379cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_LOW;
2389cd58e6bSjdc 		else
2399cd58e6bSjdc 			return ENVSYS_BATTERY_CAPACITY_NORMAL;
2409cd58e6bSjdc 	} else {
2419cd58e6bSjdc 		DPRINTF("%s unknown battery state %02x\n",
2429cd58e6bSjdc 		    __func__, gstat);
2439cd58e6bSjdc 		return ENVSYS_BATTERY_CAPACITY_NORMAL;
2449cd58e6bSjdc 	}
2459cd58e6bSjdc }
2469cd58e6bSjdc 
2479cd58e6bSjdc /* The data to read is calculated from the command and the units */
2489877af41Smacallan static void
tadpmu_sensors_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)2499877af41Smacallan tadpmu_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
2509877af41Smacallan {
2519877af41Smacallan 	int res;
2529cd58e6bSjdc 
2539877af41Smacallan 	if (edata->private > 0) {
2549a42a893Smacallan 		mutex_enter(&tadpmu_lock);
2559877af41Smacallan 		tadpmu_flush();
2569877af41Smacallan 		tadpmu_send_cmd(edata->private);
2579877af41Smacallan 		res = tadpmu_recv();
2589a42a893Smacallan 		mutex_exit(&tadpmu_lock);
2599877af41Smacallan 		if (edata->units == ENVSYS_STEMP) {
2609877af41Smacallan 			edata->value_cur = res * 1000000 + 273150000;
2619cd58e6bSjdc 		} else if (edata->units == ENVSYS_SVOLTS_DC) {
2629cd58e6bSjdc 			edata->value_cur = res * 100000;
2639cd58e6bSjdc 		} else if (edata->units == ENVSYS_BATTERY_CHARGE) {
2649cd58e6bSjdc 			if (res & GENSTAT_BATTERY_CHARGING)
2659cd58e6bSjdc 				edata->value_cur = ENVSYS_INDICATOR_TRUE;
2669cd58e6bSjdc 			else
2679cd58e6bSjdc 				edata->value_cur = ENVSYS_INDICATOR_FALSE;
2689cd58e6bSjdc 		} else if (edata->units == ENVSYS_BATTERY_CAPACITY) {
2699cd58e6bSjdc 			edata->value_cur = tadpmu_battery_capacity(res);
2709cd58e6bSjdc 		} else {
2719cd58e6bSjdc 			if (edata->units == ENVSYS_INDICATOR &&
2729cd58e6bSjdc 			    edata->private == CMD_READ_GENSTAT) {
2739cd58e6bSjdc 				if (res & GENSTAT_DC_PRESENT)
2749cd58e6bSjdc 					edata->value_cur =
2759cd58e6bSjdc 					    ENVSYS_INDICATOR_TRUE;
2769cd58e6bSjdc 				else
2779cd58e6bSjdc 					edata->value_cur =
2789cd58e6bSjdc 					    ENVSYS_INDICATOR_FALSE;
2799877af41Smacallan 			} else {
2809877af41Smacallan 				edata->value_cur = res;
2819877af41Smacallan 			}
2829cd58e6bSjdc 		}
2839877af41Smacallan 		edata->state = ENVSYS_SVALID;
2849877af41Smacallan 	} else {
2859877af41Smacallan 		edata->state = ENVSYS_SINVALID;
2869877af41Smacallan 	}
2879877af41Smacallan }
2889877af41Smacallan 
2899a42a893Smacallan static void
tadpmu_events(void * cookie)2909a42a893Smacallan tadpmu_events(void *cookie)
2919a42a893Smacallan {
2929cd58e6bSjdc 	uint8_t events, gs, vb;
2939cd58e6bSjdc 
2949a42a893Smacallan 	while (!tadpmu_dying) {
2959a42a893Smacallan 		mutex_enter(&tadpmu_lock);
2969a42a893Smacallan 		tadpmu_flush();
2979a42a893Smacallan 		tadpmu_send_cmd(CMD_READ_GENSTAT);
2989cd58e6bSjdc 		gs = tadpmu_recv();
2999cd58e6bSjdc 		tadpmu_send_cmd(CMD_READ_VBATT);
3009cd58e6bSjdc 		vb = tadpmu_recv();
3019a42a893Smacallan 		mutex_exit(&tadpmu_lock);
3029cd58e6bSjdc 
3039cd58e6bSjdc 		mutex_enter(&data_lock);
3049cd58e6bSjdc 		events = ev_data;
3059cd58e6bSjdc 		mutex_exit(&data_lock);
3069cd58e6bSjdc 		DPRINTF("%s event %02x, status %02x/%02x\n", __func__,
3079cd58e6bSjdc 		    events, gs, vb);
3089cd58e6bSjdc 
3099cd58e6bSjdc 		if (events & TADPMU_EV_PWRBUTT) {
3109cd58e6bSjdc 			mutex_enter(&data_lock);
3119cd58e6bSjdc 			ev_data &= ~TADPMU_EV_PWRBUTT;
3129cd58e6bSjdc 			mutex_exit(&data_lock);
3139cd58e6bSjdc 			sysmon_pswitch_event(&tadpmu_pbutton,
3149cd58e6bSjdc 			    PSWITCH_EVENT_PRESSED);
3159a42a893Smacallan 		}
3169cd58e6bSjdc 
3179cd58e6bSjdc 		if (events & TADPMU_EV_LID) {
3189cd58e6bSjdc 			mutex_enter(&data_lock);
3199cd58e6bSjdc 			ev_data &= ~TADPMU_EV_LID;
3209cd58e6bSjdc 			mutex_exit(&data_lock);
3219cd58e6bSjdc 			sysmon_pswitch_event(&tadpmu_lidswitch,
3229cd58e6bSjdc 			    gs & GENSTAT_LID_CLOSED ?
3239cd58e6bSjdc 		            PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED);
3249cd58e6bSjdc 		}
3259cd58e6bSjdc 
3269cd58e6bSjdc 		if (events & TADPMU_EV_DCPOWER) {
3279cd58e6bSjdc 			mutex_enter(&data_lock);
3289cd58e6bSjdc 			ev_data &= ~TADPMU_EV_DCPOWER;
3299cd58e6bSjdc 			mutex_exit(&data_lock);
3309cd58e6bSjdc 			sysmon_pswitch_event(&tadpmu_dcpower,
3319cd58e6bSjdc 			    gs & GENSTAT_DC_PRESENT ?
3329cd58e6bSjdc 		            PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED);
3339cd58e6bSjdc 		}
3349cd58e6bSjdc 
3359cd58e6bSjdc 		if (events & TADPMU_EV_BATTCHANGE) {
3369cd58e6bSjdc 			mutex_enter(&data_lock);
3379cd58e6bSjdc 			ev_data &= ~TADPMU_EV_BATTCHANGE;
3389cd58e6bSjdc 			mutex_exit(&data_lock);
3399cd58e6bSjdc 			if (gs == GENSTAT_STATE_BATTERY_DISCHARGE) {
3409cd58e6bSjdc 				if (vb < TADPMU_BATT_DIS_CAP_CRIT)
3419cd58e6bSjdc 					printf("Battery critical!\n");
3429cd58e6bSjdc 				else if (vb < TADPMU_BATT_DIS_CAP_WARN)
3439cd58e6bSjdc 					printf("Battery warning!\n");
3449cd58e6bSjdc 			}
3459cd58e6bSjdc 		}
3469cd58e6bSjdc 
3479cd58e6bSjdc 		if (events & TADPMU_EV_BATTCHARGED) {
3489cd58e6bSjdc 			mutex_enter(&data_lock);
3499cd58e6bSjdc 			ev_data &= ~TADPMU_EV_BATTCHARGED;
3509cd58e6bSjdc 			mutex_exit(&data_lock);
3519cd58e6bSjdc 			printf("Battery charged\n");
3529cd58e6bSjdc 		}
3539cd58e6bSjdc 
3549a42a893Smacallan 		tsleep(tadpmuev, 0, "tadpmuev", hz);
3559a42a893Smacallan 	}
3569a42a893Smacallan 	kthread_exit(0);
3579a42a893Smacallan }
3589a42a893Smacallan 
3599877af41Smacallan int
tadpmu_intr(void * cookie)3609e92499dSmacallan tadpmu_intr(void *cookie)
3619e92499dSmacallan {
3629e92499dSmacallan 	uint8_t s = tadpmu_status(), d;
3639e92499dSmacallan 	if (s & STATUS_INTR) {
3649e92499dSmacallan 		/* interrupt message */
3659e92499dSmacallan 		d = tadpmu_data();
3669cd58e6bSjdc 		DPRINTF("%s status change %02x\n", __func__, d);
3679cd58e6bSjdc 
3689e92499dSmacallan 		switch (d) {
3699cd58e6bSjdc 			case TADPMU_INTR_POWERBUTTON:
3709cd58e6bSjdc 				mutex_enter(&data_lock);
3719cd58e6bSjdc 				ev_data |= TADPMU_EV_PWRBUTT;;
3729cd58e6bSjdc 				mutex_exit(&data_lock);
3739e92499dSmacallan 				break;
3749cd58e6bSjdc 			case TADPMU_INTR_LID:
3759cd58e6bSjdc 				mutex_enter(&data_lock);
3769cd58e6bSjdc 				ev_data |= TADPMU_EV_LID;
3779cd58e6bSjdc 				mutex_exit(&data_lock);
3789cd58e6bSjdc 				break;
3799cd58e6bSjdc 			case TADPMU_INTR_DCPOWER:
3809cd58e6bSjdc 				mutex_enter(&data_lock);
3819cd58e6bSjdc 				ev_data |= TADPMU_EV_DCPOWER;
3829cd58e6bSjdc 				mutex_exit(&data_lock);
3839cd58e6bSjdc 				break;
3849cd58e6bSjdc 			case TADPMU_INTR_BATTERY_STATE:
3859cd58e6bSjdc 				mutex_enter(&data_lock);
3869cd58e6bSjdc 				ev_data |= TADPMU_EV_BATTCHANGE;
3879cd58e6bSjdc 				mutex_exit(&data_lock);
3889cd58e6bSjdc 				break;
3899cd58e6bSjdc 			case TADPMU_INTR_BATTERY_CHARGED:
3909cd58e6bSjdc 				mutex_enter(&data_lock);
3919cd58e6bSjdc 				ev_data |= TADPMU_EV_BATTCHARGED;
3929cd58e6bSjdc 				mutex_exit(&data_lock);
3939e92499dSmacallan 				break;
3949e92499dSmacallan 		}
3959cd58e6bSjdc 		/* Report events */
3969cd58e6bSjdc 		if (ev_data)
3979cd58e6bSjdc 			wakeup(tadpmuev);
3989e92499dSmacallan 	}
3999e92499dSmacallan 	s = tadpmu_status();
4009e92499dSmacallan 	if (s & STATUS_HAVE_DATA) {
4019e92499dSmacallan 		idata = tadpmu_data();
4029e92499dSmacallan 		ivalid = 1;
4039e92499dSmacallan 		wakeup(tadpmu);
4049e92499dSmacallan 		DPRINTF("%s data %02x\n", __func__, idata);
4059e92499dSmacallan 	}
4069e92499dSmacallan 
4079e92499dSmacallan 	return 1;
4089e92499dSmacallan }
4099e92499dSmacallan 
4109e92499dSmacallan int
tadpmu_init(bus_space_tag_t t,bus_space_handle_t hcmd,bus_space_handle_t hdata)4119877af41Smacallan tadpmu_init(bus_space_tag_t t, bus_space_handle_t hcmd, bus_space_handle_t hdata)
4129877af41Smacallan {
4139cd58e6bSjdc 	uint8_t ver;
4149877af41Smacallan 
4159877af41Smacallan 	tadpmu_iot = t;
4169877af41Smacallan 	tadpmu_hcmd = hcmd;
4179877af41Smacallan 	tadpmu_hdata = hdata;
4189877af41Smacallan 
4199877af41Smacallan 	tadpmu_flush();
4209877af41Smacallan 	delay(1000);
4219877af41Smacallan 
4229877af41Smacallan 	tadpmu_send_cmd(CMD_READ_VERSION);
4239877af41Smacallan 	ver = tadpmu_recv();
4249877af41Smacallan 	printf("Tadpole PMU Version 1.%d\n", ver);
4259877af41Smacallan 
4269877af41Smacallan 	tadpmu_send_cmd(CMD_SET_OPMODE);
4279cd58e6bSjdc 	tadpmu_send(OPMODE_UNIX);
4289877af41Smacallan 
4299cd58e6bSjdc #ifdef TADPMU_DEBUG
4309877af41Smacallan 	tadpmu_send_cmd(CMD_READ_SYSTEMP);
4319877af41Smacallan 	ver = tadpmu_recv();
4329cd58e6bSjdc 	printf("Temperature 0x%02x\n", ver);
4339877af41Smacallan 
4349877af41Smacallan 	tadpmu_send_cmd(CMD_READ_VBATT);
4359877af41Smacallan 	ver = tadpmu_recv();
4369cd58e6bSjdc 	printf("Battery voltage 0x%02x\n", ver);
4379877af41Smacallan 
4389877af41Smacallan 	tadpmu_send_cmd(CMD_READ_GENSTAT);
4399877af41Smacallan 	ver = tadpmu_recv();
4409cd58e6bSjdc 	printf("status 0x%02x\n", ver);
4419cd58e6bSjdc #endif
4429877af41Smacallan 
4439a42a893Smacallan 	mutex_init(&tadpmu_lock, MUTEX_DEFAULT, IPL_NONE);
4449cd58e6bSjdc 	mutex_init(&data_lock, MUTEX_DEFAULT, IPL_HIGH);
4459a42a893Smacallan 
4469cd58e6bSjdc 	tadpmu_sens_sme = sysmon_envsys_create();
4479cd58e6bSjdc 	tadpmu_sens_sme->sme_name = "tadpmu";
4489cd58e6bSjdc 	tadpmu_sens_sme->sme_cookie = NULL;
4499cd58e6bSjdc 	tadpmu_sens_sme->sme_refresh = tadpmu_sensors_refresh;
4509877af41Smacallan 
4519cd58e6bSjdc 	tadpmu_acad_sme = sysmon_envsys_create();
4529cd58e6bSjdc 	tadpmu_acad_sme->sme_name = "ac adapter";
4539cd58e6bSjdc 	tadpmu_acad_sme->sme_cookie = NULL;
4549cd58e6bSjdc 	tadpmu_acad_sme->sme_refresh = tadpmu_sensors_refresh;
4559cd58e6bSjdc 	tadpmu_acad_sme->sme_class = SME_CLASS_ACADAPTER;
4569cd58e6bSjdc 
4579cd58e6bSjdc 	tadpmu_batt_sme = sysmon_envsys_create();
4589cd58e6bSjdc 	tadpmu_batt_sme->sme_name = "battery";
4599cd58e6bSjdc 	tadpmu_batt_sme->sme_cookie = NULL;
4609cd58e6bSjdc 	tadpmu_batt_sme->sme_refresh = tadpmu_sensors_refresh;
4619cd58e6bSjdc 	tadpmu_batt_sme->sme_class = SME_CLASS_BATTERY;
4629cd58e6bSjdc 
4639cd58e6bSjdc 	tadpmu_sensors[0].state = ENVSYS_SINVALID;
4649877af41Smacallan 	tadpmu_sensors[0].units = ENVSYS_STEMP;
4659877af41Smacallan 	tadpmu_sensors[0].private = CMD_READ_SYSTEMP;
4669877af41Smacallan 	strcpy(tadpmu_sensors[0].desc, "systemp");
4679cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_sens_sme, &tadpmu_sensors[0]);
4689cd58e6bSjdc 
4699cd58e6bSjdc 	tadpmu_sensors[1].state = ENVSYS_SINVALID;
4709cd58e6bSjdc 	tadpmu_sensors[1].units = ENVSYS_INDICATOR;
4719cd58e6bSjdc 	tadpmu_sensors[1].private = CMD_READ_FAN_EN;
4729cd58e6bSjdc 	strcpy(tadpmu_sensors[1].desc, "fan on");
4739cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_sens_sme, &tadpmu_sensors[1]);
4749cd58e6bSjdc 
4759cd58e6bSjdc 	tadpmu_sensors[2].state = ENVSYS_SINVALID;
4769cd58e6bSjdc 	tadpmu_sensors[2].units = ENVSYS_INDICATOR;
4779cd58e6bSjdc 	tadpmu_sensors[2].private = CMD_READ_GENSTAT;
4789cd58e6bSjdc 	strcpy(tadpmu_sensors[2].desc, "DC power");
4799cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_acad_sme, &tadpmu_sensors[2]);
4809cd58e6bSjdc 
4819cd58e6bSjdc 	tadpmu_sensors[3].state = ENVSYS_SINVALID;
4829cd58e6bSjdc 	tadpmu_sensors[3].units = ENVSYS_SVOLTS_DC;
4839cd58e6bSjdc 	tadpmu_sensors[3].private = CMD_READ_VBATT;
4849cd58e6bSjdc 	strcpy(tadpmu_sensors[3].desc, "Vbatt");
4859cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_batt_sme, &tadpmu_sensors[3]);
4869cd58e6bSjdc 
4879cd58e6bSjdc 	tadpmu_sensors[4].state = ENVSYS_SINVALID;
4889cd58e6bSjdc 	tadpmu_sensors[4].units = ENVSYS_BATTERY_CAPACITY;
4899cd58e6bSjdc 	tadpmu_sensors[4].private = CMD_READ_GENSTAT;
4909cd58e6bSjdc 	/* We must provide an initial value for battery capacity */
4919cd58e6bSjdc 	tadpmu_sensors[4].value_cur = ENVSYS_BATTERY_CAPACITY_NORMAL;
4929cd58e6bSjdc 	strcpy(tadpmu_sensors[4].desc, "capacity");
4939cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_batt_sme, &tadpmu_sensors[4]);
4949cd58e6bSjdc 
4959cd58e6bSjdc 	tadpmu_sensors[5].state = ENVSYS_SINVALID;
4969cd58e6bSjdc 	tadpmu_sensors[5].units = ENVSYS_BATTERY_CHARGE;
4979cd58e6bSjdc 	tadpmu_sensors[5].private = CMD_READ_GENSTAT;
4989cd58e6bSjdc 	strcpy(tadpmu_sensors[5].desc, "charging");
4999cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_batt_sme, &tadpmu_sensors[5]);
5009cd58e6bSjdc 
5019877af41Smacallan #ifdef TADPMU_DEBUG
5029cd58e6bSjdc 	tadpmu_sensors[6].state = ENVSYS_SINVALID;
5039cd58e6bSjdc 	tadpmu_sensors[6].units = ENVSYS_INTEGER;
5049cd58e6bSjdc 	tadpmu_sensors[6].private = CMD_READ_GENSTAT;
5059cd58e6bSjdc 	strcpy(tadpmu_sensors[6].desc, "genstat");
5069cd58e6bSjdc 	sysmon_envsys_sensor_attach(tadpmu_sens_sme, &tadpmu_sensors[6]);
5079877af41Smacallan #endif
5089cd58e6bSjdc 
5099cd58e6bSjdc 	sysmon_envsys_register(tadpmu_sens_sme);
5109cd58e6bSjdc 	sysmon_envsys_register(tadpmu_acad_sme);
5119cd58e6bSjdc 	sysmon_envsys_register(tadpmu_batt_sme);
5129877af41Smacallan 
5139e92499dSmacallan 	sysmon_task_queue_init();
5149e92499dSmacallan 	memset(&tadpmu_pbutton, 0, sizeof(struct sysmon_pswitch));
5159a42a893Smacallan 	tadpmu_pbutton.smpsw_name = "power";
5169e92499dSmacallan 	tadpmu_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
5179e92499dSmacallan 	if (sysmon_pswitch_register(&tadpmu_pbutton) != 0)
5189e92499dSmacallan 		aprint_error(
5199e92499dSmacallan 		    "unable to register power button with sysmon\n");
5209e92499dSmacallan 
5219cd58e6bSjdc 	memset(&tadpmu_lidswitch, 0, sizeof(struct sysmon_pswitch));
5229a42a893Smacallan 	tadpmu_lidswitch.smpsw_name = "lid";
5239a42a893Smacallan 	tadpmu_lidswitch.smpsw_type = PSWITCH_TYPE_LID;
5249a42a893Smacallan 	if (sysmon_pswitch_register(&tadpmu_lidswitch) != 0)
5259a42a893Smacallan 		aprint_error(
5269a42a893Smacallan 		    "unable to register lid switch with sysmon\n");
5279a42a893Smacallan 
5289cd58e6bSjdc 	memset(&tadpmu_dcpower, 0, sizeof(struct sysmon_pswitch));
5299cd58e6bSjdc 	tadpmu_dcpower.smpsw_name = "AC adapter";
5309cd58e6bSjdc 	tadpmu_dcpower.smpsw_type = PSWITCH_TYPE_ACADAPTER;
5319cd58e6bSjdc 	if (sysmon_pswitch_register(&tadpmu_dcpower) != 0)
5329cd58e6bSjdc 		aprint_error(
5339cd58e6bSjdc 		    "unable to register AC adapter with sysmon\n");
5349cd58e6bSjdc 
5359a42a893Smacallan 	kthread_create(PRI_NONE, 0, curcpu(), tadpmu_events, NULL,
5369a42a893Smacallan 	    &tadpmu_thread, "tadpmu_events");
5379a42a893Smacallan 
5389877af41Smacallan 	return 0;
5399877af41Smacallan }
540e35ff9bdSmacallan #endif /* HAVE_TADPMU */
541