xref: /netbsd/sys/arch/hpcmips/vr/vrc4172pwm.c (revision 5f819ca3)
1 /*	$NetBSD: vrc4172pwm.c,v 1.22 2012/10/27 17:17:55 chs Exp $	*/
2 
3 /*
4  * Copyright (c) 2000,2001 SATO Kazumi. 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 AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: vrc4172pwm.c,v 1.22 2012/10/27 17:17:55 chs Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 #include <sys/reboot.h>
35 
36 #include <machine/bus.h>
37 #include <machine/config_hook.h>
38 #include <machine/platid.h>
39 #include <machine/platid_mask.h>
40 
41 #include <hpcmips/vr/vr.h>
42 #include <hpcmips/vr/vripif.h>
43 #include <hpcmips/vr/vrc4172pwmvar.h>
44 #include <hpcmips/vr/vrc4172pwmreg.h>
45 
46 #include "locators.h"
47 
48 #ifdef VRC2PWMDEBUG
49 #ifndef VRC2PWMDEBUG_CONF
50 #define VRC2PWMDEBUG_CONF 0
51 #endif /* VRC2PWMDEBUG_CONF */
52 int vrc4172pwmdebug = VRC2PWMDEBUG_CONF;
53 #define DPRINTF(arg) if (vrc4172pwmdebug) printf arg;
54 #define VPRINTF(arg) if (bootverbose||vrc4172pwmdebug) printf arg;
55 #define VDUMPREG(arg) if (bootverbose||vrc4172pwmdebug) vrc4172pwm_dumpreg(arg);
56 #else /* VRC2PWMDEBUG */
57 #define DPRINTF(arg)
58 #define VPRINTF(arg) if (bootverbose) printf arg;
59 #define VDUMPREG(arg) if (bootverbose) vrc4172pwm_dumpreg(arg);
60 #endif /* VRC2PWMDEBUG */
61 
62 static int vrc4172pwmprobe(device_t, cfdata_t, void *);
63 static void vrc4172pwmattach(device_t, device_t, void *);
64 
65 static void vrc4172pwm_write(struct vrc4172pwm_softc *, int, unsigned short);
66 static unsigned short vrc4172pwm_read(struct vrc4172pwm_softc *, int);
67 
68 static int vrc4172pwm_event(void *, int, long, void *);
69 static int vrc4172pwm_pmevent(void *, int, long, void *);
70 
71 static void vrc4172pwm_dumpreg(struct vrc4172pwm_softc *);
72 static void vrc4172pwm_init_brightness(struct vrc4172pwm_softc *);
73 void vrc4172pwm_light(struct vrc4172pwm_softc *, int);
74 int vrc4172pwm_get_light(struct vrc4172pwm_softc *);
75 int vrc4172pwm_get_brightness(struct vrc4172pwm_softc *);
76 void vrc4172pwm_set_brightness(struct vrc4172pwm_softc *, int);
77 int vrc4172pwm_rawduty2brightness(struct vrc4172pwm_softc *);
78 int vrc4172pwm_brightness2rawduty(struct vrc4172pwm_softc *);
79 struct vrc4172pwm_param * vrc4172pwm_getparam(void);
80 void vrc4172pwm_dumpreg(struct vrc4172pwm_softc *);
81 
82 CFATTACH_DECL_NEW(vrc4172pwm, sizeof(struct vrc4172pwm_softc),
83     vrc4172pwmprobe, vrc4172pwmattach, NULL, NULL);
84 
85 /*
86  * platform related parameters
87  */
88 struct vrc4172pwm_param vrc4172pwm_mcr520_param = {
89 	1, /* probe broken */
90 	8, /* levels */
91 	{ 0x16, 0x1f, 0x24, 0x2a, 0x2f, 0x34, 0x3a, 0x3f }
92 };
93 
94 struct vrc4172pwm_param vrc4172pwm_mcr530_param = {
95 	0,
96 	8, /* levels */
97 	{ 0x16, 0x1b, 0x20, 0x25, 0x2a, 0x30, 0x37, 0x3f }
98 };
99 
100 struct vrc4172pwm_param vrc4172pwm_mcr700_param = {
101 	1, /* probe broken */
102 	8, /* levels */
103 	{ 0x12, 0x15, 0x18, 0x1d, 0x24, 0x2d, 0x38, 0x3f }
104 };
105 
106 struct vrc4172pwm_param vrc4172pwm_sigmarion_param = {
107 	0,
108 	8, /* levels */
109 	{ 0xe, 0x13, 0x18, 0x1c, 0x23, 0x29, 0x32, 0x3f }
110 };
111 
112 
113 struct platid_data vrc4172pwm_platid_param_table[] = {
114 	{ &platid_mask_MACH_NEC_MCR_430,	&vrc4172pwm_mcr530_param},
115 	{ &platid_mask_MACH_NEC_MCR_510,	&vrc4172pwm_mcr520_param},
116 	{ &platid_mask_MACH_NEC_MCR_520,	&vrc4172pwm_mcr520_param},
117 	{ &platid_mask_MACH_NEC_MCR_520A,	&vrc4172pwm_mcr520_param},
118 	{ &platid_mask_MACH_NEC_MCR_530,	&vrc4172pwm_mcr530_param},
119 	{ &platid_mask_MACH_NEC_MCR_530A,	&vrc4172pwm_mcr530_param},
120 	{ &platid_mask_MACH_NEC_MCR_SIGMARION,	&vrc4172pwm_sigmarion_param},
121 	{ &platid_mask_MACH_NEC_MCR_700,	&vrc4172pwm_mcr700_param},
122 	{ &platid_mask_MACH_NEC_MCR_700A,	&vrc4172pwm_mcr700_param},
123 	{ &platid_mask_MACH_NEC_MCR_730,	&vrc4172pwm_mcr700_param},
124 	{ &platid_mask_MACH_NEC_MCR_730A,	&vrc4172pwm_mcr700_param},
125 	{ NULL, NULL}
126 };
127 
128 struct vrc4172pwm_softc *this_pwm;
129 
130 static inline void
vrc4172pwm_write(struct vrc4172pwm_softc * sc,int port,unsigned short val)131 vrc4172pwm_write(struct vrc4172pwm_softc *sc, int port, unsigned short val)
132 {
133 
134 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
135 }
136 
137 static inline unsigned short
vrc4172pwm_read(struct vrc4172pwm_softc * sc,int port)138 vrc4172pwm_read(struct vrc4172pwm_softc *sc, int port)
139 {
140 
141 	return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
142 }
143 
144 static int
vrc4172pwmprobe(device_t parent,cfdata_t cf,void * aux)145 vrc4172pwmprobe(device_t parent, cfdata_t cf, void *aux)
146 {
147 	platid_mask_t mask;
148 	struct vrip_attach_args *va = aux;
149 	bus_space_handle_t ioh;
150 #ifdef VRC4172PWM_BROKEN_PROBE
151 	int probe = 0;
152 #else /* VRC4172PWM_BROKEN_PROBE */
153 	int probe = 1;
154 #endif /* VRC4172PWM_BROKEN_PROBE */
155 	int data;
156 	int data2;
157 	struct vrc4172pwm_param *param;
158 	int ret = 0;
159 
160 	if (va->va_addr == VRIPIFCF_ADDR_DEFAULT)
161 		return (0);
162 
163 	if (cf->cf_loc[VRIPIFCF_PLATFORM] == 0)
164 		return (0);
165 	if (cf->cf_loc[VRIPIFCF_PLATFORM] != -1) { /* if specify */
166 		mask = PLATID_DEREF(cf->cf_loc[VRIPIFCF_PLATFORM]);
167 		VPRINTF(("vrc4172pwmprobe: check platid\n"));
168 		if (platid_match(&platid, &mask) == 0)
169 			return (0);
170 		param = vrc4172pwm_getparam();
171 		if (param != NULL && param->brokenprobe)
172 			probe = 0;
173 	}
174 	if (probe) {
175 		if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0,
176 		    &ioh)) {
177 			return (0);
178 		}
179 		data =  bus_space_read_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN);
180 		bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, 0xff);
181 		if ((data2 = bus_space_read_2(va->va_iot, ioh,
182 		    VRC2_PWM_LCDDUTYEN)) == VRC2_PWM_LCDEN_MASK) {
183 			VPRINTF(("vrc4172pwmprobe:"
184 			    " VRC2_PWM_LCDDUTYEN found\n"));
185 			ret = 1;
186 		} else {
187 			VPRINTF(("vrc4172pwmprobe: VRC2_PWM_LCDDUTYEN"
188 			    " not found org=%x, data=%x!=%x\n",
189 			    data, data2, VRC2_PWM_LCDEN_MASK));
190 		}
191 		bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, data);
192 		bus_space_unmap(va->va_iot, ioh, va->va_size);
193 	} else
194 		ret = 1;
195 	VPRINTF(("vrc4172pwmprobe: return %d\n", ret));
196 
197 	return (ret);
198 }
199 
200 static void
vrc4172pwmattach(device_t parent,device_t self,void * aux)201 vrc4172pwmattach(device_t parent, device_t self, void *aux)
202 {
203 	struct vrc4172pwm_softc *sc = device_private(self);
204 	struct vrip_attach_args *va = aux;
205 
206 	bus_space_tag_t iot = va->va_iot;
207 	bus_space_handle_t ioh;
208 
209 	if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
210 		printf(": can't map bus space\n");
211 		return;
212 	}
213 
214 	sc->sc_iot = iot;
215 	sc->sc_ioh = ioh;
216 
217 	printf("\n");
218 
219 	VDUMPREG(sc);
220 	/* basic setup */
221 	sc->sc_pmhook = config_hook(CONFIG_HOOK_PMEVENT,
222 	    CONFIG_HOOK_PMEVENT_HARDPOWER, CONFIG_HOOK_SHARE,
223 	    vrc4172pwm_pmevent, sc);
224 	sc->sc_lcdhook = config_hook(CONFIG_HOOK_POWERCONTROL,
225 	    CONFIG_HOOK_POWERCONTROL_LCDLIGHT, CONFIG_HOOK_SHARE,
226 	    vrc4172pwm_event, sc);
227 	sc->sc_getlcdhook = config_hook(CONFIG_HOOK_GET,
228 	    CONFIG_HOOK_POWER_LCDLIGHT, CONFIG_HOOK_SHARE,
229 	    vrc4172pwm_event, sc);
230 	sc->sc_sethook = config_hook(CONFIG_HOOK_SET,
231 	    CONFIG_HOOK_BRIGHTNESS, CONFIG_HOOK_SHARE,
232 	    vrc4172pwm_event, sc);
233 	sc->sc_gethook = config_hook(CONFIG_HOOK_GET,
234 	    CONFIG_HOOK_BRIGHTNESS, CONFIG_HOOK_SHARE,
235 	    vrc4172pwm_event, sc);
236 	sc->sc_getmaxhook = config_hook(CONFIG_HOOK_GET,
237 	    CONFIG_HOOK_BRIGHTNESS_MAX, CONFIG_HOOK_SHARE,
238 	    vrc4172pwm_event, sc);
239 
240 	vrc4172pwm_init_brightness(sc);
241 	if (sc->sc_param == NULL)
242 		printf("vrc4172pwm: NO parameter found. DISABLE pwm control\n");
243 	this_pwm = sc;
244 }
245 
246 /*
247  * get platform related brightness paramerters
248  */
249 struct vrc4172pwm_param *
vrc4172pwm_getparam(void)250 vrc4172pwm_getparam(void)
251 {
252 	struct platid_data *p;
253 
254 	if ((p = platid_search_data(&platid, vrc4172pwm_platid_param_table)))
255 		return (p->data);
256 
257 	return (NULL);
258 }
259 
260 /*
261  *
262  * Initialize PWM brightness parameters
263  *
264  */
265 void
vrc4172pwm_init_brightness(struct vrc4172pwm_softc * sc)266 vrc4172pwm_init_brightness(struct vrc4172pwm_softc *sc)
267 {
268 	sc->sc_param = vrc4172pwm_getparam();
269 	sc->sc_raw_freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
270 	sc->sc_raw_duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
271 	sc->sc_brightness = vrc4172pwm_rawduty2brightness(sc);
272 	sc->sc_light = vrc4172pwm_get_light(sc);
273 	DPRINTF(("vrc4172pwm_init_brightness: param=0x%x, freq=0x%x,"
274 	    " duty=0x%x, blightness=%d light=%d\n", (int)sc->sc_param,
275 	    sc->sc_raw_freq, sc->sc_raw_duty, sc->sc_brightness,
276 	    sc->sc_light));
277 }
278 /*
279  * backlight on/off
280  */
281 void
vrc4172pwm_light(struct vrc4172pwm_softc * sc,int on)282 vrc4172pwm_light(struct vrc4172pwm_softc *sc, int on)
283 {
284 	int brightness;
285 
286 	DPRINTF(("vrc4172pwm_light: %s\n", on?"ON":"OFF"));
287 	if (on) {
288 		vrc4172pwm_set_brightness(sc, sc->sc_brightness);
289 		vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_EN);
290 	} else {
291 		brightness = sc->sc_brightness; /* save */
292 		vrc4172pwm_set_brightness(sc, 0);
293 		/* need this, break sc->sc_brightness */
294 		sc->sc_brightness = brightness; /* resume */
295 		vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_DIS);
296 	}
297 	sc->sc_light = on;
298 }
299 
300 /*
301  * get backlight on/off
302  */
303 int
vrc4172pwm_get_light(struct vrc4172pwm_softc * sc)304 vrc4172pwm_get_light(struct vrc4172pwm_softc *sc)
305 {
306 
307 	return (VRC2_PWM_LCDEN_MASK&vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN));
308 }
309 
310 /*
311  * set brightness
312  */
313 void
vrc4172pwm_set_brightness(struct vrc4172pwm_softc * sc,int val)314 vrc4172pwm_set_brightness(struct vrc4172pwm_softc *sc, int val)
315 {
316 	int raw;
317 
318 	if (sc->sc_param == NULL)
319 		return;
320 	if (val < 0)
321 		val = 0;
322 	if (val > VRC2_PWM_MAX_BRIGHTNESS)
323 		val = VRC2_PWM_MAX_BRIGHTNESS;
324 	if (val > sc->sc_param->n_brightness)
325 		val = sc->sc_param->n_brightness;
326 	sc->sc_brightness = val;
327 	raw = vrc4172pwm_brightness2rawduty(sc);
328 	vrc4172pwm_write(sc, VRC2_PWM_LCDDUTY, raw);
329 	DPRINTF(("vrc4172pwm_set_brightness: val=%d raw=0x%x\n", val, raw));
330 }
331 
332 /*
333  * get brightness
334  */
335 int
vrc4172pwm_get_brightness(struct vrc4172pwm_softc * sc)336 vrc4172pwm_get_brightness(struct vrc4172pwm_softc *sc)
337 {
338 
339 	if (sc->sc_param == NULL)
340 		return (VRC2_PWM_MAX_BRIGHTNESS);
341 
342 	return (sc->sc_brightness);
343 }
344 
345 /*
346  * PWM duty to brightness
347  */
348 int
vrc4172pwm_rawduty2brightness(struct vrc4172pwm_softc * sc)349 vrc4172pwm_rawduty2brightness(struct vrc4172pwm_softc *sc)
350 {
351 	int i;
352 
353 	if (sc->sc_param == NULL)
354 		return (VRC2_PWM_MAX_BRIGHTNESS);
355 	for (i = 0; i < sc->sc_param->n_brightness; i++) {
356 		if (sc->sc_raw_duty <= sc->sc_param->bvalues[i])
357 			break;
358 	}
359 	if (i >= sc->sc_param->n_brightness-1)
360 		return (sc->sc_param->n_brightness-1);
361 	else
362 		return (i);
363 
364 }
365 
366 /*
367  * brightness to raw duty
368  */
369 int
vrc4172pwm_brightness2rawduty(struct vrc4172pwm_softc * sc)370 vrc4172pwm_brightness2rawduty(struct vrc4172pwm_softc *sc)
371 {
372 
373 	if (sc->sc_param == NULL)
374 		return (VRC2_PWM_LCDDUTY_MASK);
375 
376 	return (sc->sc_param->bvalues[sc->sc_brightness]);
377 }
378 
379 
380 /*
381  * PWM config hook events
382  *
383  */
384 int
vrc4172pwm_event(void * ctx,int type,long id,void * msg)385 vrc4172pwm_event(void *ctx, int type, long id, void *msg)
386 {
387 	struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
388         int why =(int)msg;
389 
390 	if (type == CONFIG_HOOK_POWERCONTROL
391 	    && id == CONFIG_HOOK_POWERCONTROL_LCDLIGHT) {
392 		DPRINTF(("vrc4172pwm:POWERCONTROL_LCDLIGHT: %d\n", why));
393 		vrc4172pwm_light(sc, why);
394 	} else if (type == CONFIG_HOOK_GET
395 	    && id == CONFIG_HOOK_POWER_LCDLIGHT) {
396 		*(int *)msg = vrc4172pwm_get_light(sc);
397 		DPRINTF(("vrc4172pwm:GET LCDLIGHT: %d\n", *(int *)msg));
398 	} else if (type == CONFIG_HOOK_GET
399 	    && id == CONFIG_HOOK_BRIGHTNESS) {
400 		*(int *)msg = vrc4172pwm_get_brightness(sc);
401 		DPRINTF(("vrc4172pwm:GET BRIGHTNESS: %d\n", *(int *)msg));
402 	} else if (type == CONFIG_HOOK_GET
403 	    && id == CONFIG_HOOK_BRIGHTNESS_MAX) {
404 		if (sc->sc_param == NULL)
405 			*(int *)msg = VRC2_PWM_MAX_BRIGHTNESS;
406 		else
407 			*(int *)msg = sc->sc_param->n_brightness-1;
408 		DPRINTF(("vrc4172pwm:GET MAX BRIGHTNESS: %d\n", *(int *)msg));
409 	} else if (type == CONFIG_HOOK_SET
410 	    && id == CONFIG_HOOK_BRIGHTNESS) {
411 		DPRINTF(("vrc4172pwm:SET BRIGHTNESS: %d\n", *(int *)msg));
412 		vrc4172pwm_set_brightness(sc, *(int *)msg);
413 	} else {
414 		DPRINTF(("vrc4172pwm:unknown event: type %d id %ld\n",
415 		    type, id));
416 		return (1);
417 	}
418 
419         return (0);
420 }
421 
422 /*
423  * PWM config hook events
424  *
425  */
426 int
vrc4172pwm_pmevent(void * ctx,int type,long id,void * msg)427 vrc4172pwm_pmevent(void *ctx, int type, long id, void *msg)
428 {
429 	struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
430         int why =(int)msg;
431 
432 	if (type != CONFIG_HOOK_PMEVENT)
433 		return (1);
434 
435         switch (why) {
436 	case PWR_STANDBY:
437 	case PWR_SUSPEND:
438 		sc->sc_light_save = sc->sc_light;
439 		vrc4172pwm_light(sc, 0);
440 		break;
441 	case PWR_RESUME:
442 		vrc4172pwm_light(sc, sc->sc_light_save);
443 		break;
444 	default:
445 		return (1);
446         }
447 
448         return (0);
449 }
450 
451 /*
452  * dump pwm registers
453  */
454 void
vrc4172pwm_dumpreg(struct vrc4172pwm_softc * sc)455 vrc4172pwm_dumpreg(struct vrc4172pwm_softc *sc)
456 {
457 	int en, freq, duty;
458 
459 	en = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
460 	freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
461 	duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
462 
463 	printf("vrc4172pwm: dumpreg: lightenable = %d,"
464 	    " freq = 0x%x, duty = 0x%x\n", en, freq, duty);
465 }
466 
467 /* end */
468