psh3pwr.c revision 1.1
1/* $NetBSD: psh3pwr.c,v 1.1 2007/09/24 16:16:42 kiyohara Exp $ */ 2/* 3 * Copyright (c) 2005, 2007 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: psh3pwr.c,v 1.1 2007/09/24 16:16:42 kiyohara Exp $"); 31 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/device.h> 35#include <sys/systm.h> 36#include <sys/callout.h> 37 38#include <machine/platid.h> 39#include <machine/platid_mask.h> 40 41#include <dev/sysmon/sysmonvar.h> 42 43#include <sh3/exception.h> 44#include <sh3/intcreg.h> 45#include <sh3/pfcreg.h> 46 47#include <sh3/dev/adcvar.h> 48 49 50#ifdef PSH3PWR_DEBUG 51#define DPRINTF(arg) printf arg 52#else 53#define DPRINTF(arg) ((void)0) 54#endif 55 56 57/* A/D covnerter channels to get power stats from */ 58#define ADC_CHANNEL_BATTERY 3 59 60/* On/Off bit for Green LED. pin 7 in SH7709 GPIO port H. */ 61#define PSH3_GREEN_LED_ON 0x80 62 63/* 64 * XXXX: 65 * WindowsCE seem to be using this as a flag. 66 * pin 6 in SH7709 GPIO port SCPDR. 67 */ 68#define PSH3PWR_PLUG_OUT 0x40 69 70/* warn that main battery is low after drops below this value */ 71#define PSH3PWR_BATTERY_WARNING_THRESHOLD 200 72 73 74struct psh3pwr_softc { 75 struct device sc_dev; 76 77 struct callout sc_poll_ch; 78 void *sc_ih_pin; 79 void *sc_ih_pout; 80 81 int sc_plug; /* In/Out flug */ 82 int sc_capacity; 83 84 struct sysmon_envsys sc_sysmon; 85 struct envsys_data sc_data; 86}; 87 88static int psh3pwr_match(struct device *, struct cfdata *, void *); 89static void psh3pwr_attach(struct device *, struct device *, void *); 90 91CFATTACH_DECL(psh3pwr, sizeof(struct psh3pwr_softc), 92 psh3pwr_match, psh3pwr_attach, NULL, NULL); 93 94static int psh3pwr_intr_plug_out(void *); 95static int psh3pwr_intr_plug_in(void *); 96static void psh3pwr_poll_callout(void *); 97static void psh3pwr_sleep(void *); 98static int psh3pwr_gtredata(struct sysmon_envsys *, envsys_data_t *); 99 100 101static int 102psh3pwr_match(struct device *parent, struct cfdata *cfp, void *aux) 103{ 104 105 if (!platid_match(&platid, &platid_mask_MACH_HITACHI_PERSONA)) 106 return 0; 107 108 if (strcmp(cfp->cf_name, "psh3pwr") != 0) 109 return 0; 110 111 return 1; 112} 113 114 115static void 116psh3pwr_attach(struct device *parent, struct device *self, void *aux) 117{ 118 extern void (*__sleep_func)(void *); 119 extern void *__sleep_ctx; 120 struct psh3pwr_softc *sc = (struct psh3pwr_softc *)self; 121 uint8_t phdr, scpdr; 122 123 /* regisiter sleep function to APM */ 124 __sleep_func = psh3pwr_sleep; 125 __sleep_ctx = self; 126 127 callout_init(&sc->sc_poll_ch, 0); 128 callout_setfunc(&sc->sc_poll_ch, psh3pwr_poll_callout, sc); 129 130 phdr = _reg_read_1(SH7709_PHDR); 131 _reg_write_1(SH7709_PHDR, phdr | PSH3_GREEN_LED_ON); 132 133 printf("\n"); 134 135 sc->sc_ih_pout = intc_intr_establish(SH7709_INTEVT2_IRQ0, 136 IST_EDGE, IPL_TTY, psh3pwr_intr_plug_out, sc); 137 sc->sc_ih_pin = intc_intr_establish(SH7709_INTEVT2_IRQ1, 138 IST_EDGE, IPL_TTY, psh3pwr_intr_plug_in, sc); 139 140 /* XXXX: WindowsCE sets this bit. */ 141 scpdr = _reg_read_1(SH7709_SCPDR); 142 if (scpdr & PSH3PWR_PLUG_OUT) { 143 sc->sc_plug = 0; 144 printf("%s: plug status: out\n", device_xname(&sc->sc_dev)); 145 } else { 146 sc->sc_plug = 1; 147 printf("%s: plug status: in\n", device_xname(&sc->sc_dev)); 148 } 149 psh3pwr_poll_callout(sc); 150 151 sc->sc_data.sensor = 0; 152 sc->sc_data.units = ENVSYS_INDICATOR; 153 sc->sc_data.state = ENVSYS_SVALID; 154 sc->sc_data.value_cur = sc->sc_plug; 155 snprintf(sc->sc_data.desc, sizeof(sc->sc_data.desc), 156 "%s %s", device_xname(&sc->sc_dev), "plug"); 157 158 sc->sc_sysmon.sme_sensor_data = &sc->sc_data; 159 sc->sc_sysmon.sme_name = device_xname(&sc->sc_dev); 160 sc->sc_sysmon.sme_cookie = sc; 161 sc->sc_sysmon.sme_gtredata = psh3pwr_gtredata; 162 sc->sc_sysmon.sme_nsensors = 163 sizeof(sc->sc_data) / sizeof(struct envsys_data); 164 165 if (sysmon_envsys_register(&sc->sc_sysmon)) 166 aprint_error("%s: unable to register with sysmon\n", 167 device_xname(&sc->sc_dev)); 168} 169 170 171static int 172psh3pwr_intr_plug_out(void *self) 173{ 174 struct psh3pwr_softc *sc = (struct psh3pwr_softc *)self; 175 uint8_t irr0, scpdr; 176 177 irr0 = _reg_read_1(SH7709_IRR0); 178 if (!(irr0 & IRR0_IRQ0)) { 179 return 0; 180 } 181 _reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ0); 182 183 /* XXXX: WindowsCE sets this bit. */ 184 scpdr = _reg_read_1(SH7709_SCPDR); 185 _reg_write_1(SH7709_SCPDR, scpdr | PSH3PWR_PLUG_OUT); 186 187 sc->sc_plug = 0; 188 DPRINTF(("%s: plug out\n", device_xname(&sc->sc_dev))); 189 190 return 1; 191} 192 193static int 194psh3pwr_intr_plug_in(void *self) 195{ 196 struct psh3pwr_softc *sc = (struct psh3pwr_softc *)self; 197 uint8_t irr0, scpdr; 198 199 irr0 = _reg_read_1(SH7709_IRR0); 200 if (!(irr0 & IRR0_IRQ1)) 201 return 0; 202 _reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ1); 203 204 /* XXXX: WindowsCE sets this bit. */ 205 scpdr = _reg_read_1(SH7709_SCPDR); 206 _reg_write_1(SH7709_SCPDR, scpdr & ~PSH3PWR_PLUG_OUT); 207 208 sc->sc_plug = 1; 209 DPRINTF(("%s: plug in\n", device_xname(&sc->sc_dev))); 210 211 return 1; 212} 213 214void 215psh3pwr_sleep(void *self) 216{ 217 /* splhigh on entry */ 218 extern void pfckbd_poll_hitachi_power(void); 219 220 uint8_t phdr; 221 222 phdr = _reg_read_1(SH7709_PHDR); 223 _reg_write_1(SH7709_PHDR, phdr & ~PSH3_GREEN_LED_ON); 224 225 pfckbd_poll_hitachi_power(); 226 227 phdr = _reg_read_1(SH7709_PHDR); 228 _reg_write_1(SH7709_PHDR, phdr | PSH3_GREEN_LED_ON); 229} 230 231volatile int psh3pwr_poll_verbose = 0; /* XXX: tweak from ddb */ 232 233static void 234psh3pwr_poll_callout(void *self) 235{ 236 struct psh3pwr_softc *sc = (struct psh3pwr_softc *)self; 237 int s; 238 239 s = spltty(); 240 sc->sc_capacity = adc_sample_channel(ADC_CHANNEL_BATTERY); 241 splx(s); 242 243 if (psh3pwr_poll_verbose != 0) 244 printf_nolog("%s: main=%-4d\n", 245 device_xname(&sc->sc_dev), sc->sc_capacity); 246 247 if (!sc->sc_plug && sc->sc_capacity < PSH3PWR_BATTERY_WARNING_THRESHOLD) 248 printf("%s: WARNING: main battery %d is low!\n", 249 device_xname(&sc->sc_dev), sc->sc_capacity); 250 251 callout_schedule(&sc->sc_poll_ch, 5 * hz); 252} 253 254static int 255psh3pwr_gtredata(struct sysmon_envsys *sme, envsys_data_t *edata) 256{ 257 struct psh3pwr_softc *sc = sme->sme_cookie; 258 259 edata->value_cur = sc->sc_plug; 260 261 return 0; 262} 263