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
74 struct 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
88 static int psh3pwr_match(struct device *, struct cfdata *, void *);
89 static void psh3pwr_attach(struct device *, struct device *, void *);
90
91 CFATTACH_DECL(psh3pwr, sizeof(struct psh3pwr_softc),
92 psh3pwr_match, psh3pwr_attach, NULL, NULL);
93
94 static int psh3pwr_intr_plug_out(void *);
95 static int psh3pwr_intr_plug_in(void *);
96 static void psh3pwr_poll_callout(void *);
97 static void psh3pwr_sleep(void *);
98 static int psh3pwr_gtredata(struct sysmon_envsys *, envsys_data_t *);
99
100
101 static int
102 psh3pwr_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
115 static void
116 psh3pwr_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
171 static int
172 psh3pwr_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
193 static int
194 psh3pwr_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
214 void
215 psh3pwr_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
231 volatile int psh3pwr_poll_verbose = 0; /* XXX: tweak from ddb */
232
233 static void
234 psh3pwr_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
254 static int
255 psh3pwr_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