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