1*4c494f76Srjs /* $NetBSD: j720lcd.c,v 1.5 2009/05/29 14:15:45 rjs Exp $ */
2547e1f66Speter
3547e1f66Speter /*-
4547e1f66Speter * Copyright (c) 2006 The NetBSD Foundation, Inc.
5547e1f66Speter * All rights reserved.
6547e1f66Speter *
7547e1f66Speter * This code is derived from software contributed to The NetBSD Foundation
8547e1f66Speter * by IWAMOTO Toshihiro.
9547e1f66Speter *
10547e1f66Speter * Redistribution and use in source and binary forms, with or without
11547e1f66Speter * modification, are permitted provided that the following conditions
12547e1f66Speter * are met:
13547e1f66Speter * 1. Redistributions of source code must retain the above copyright
14547e1f66Speter * notice, this list of conditions and the following disclaimer.
15547e1f66Speter * 2. Redistributions in binary form must reproduce the above copyright
16547e1f66Speter * notice, this list of conditions and the following disclaimer in the
17547e1f66Speter * documentation and/or other materials provided with the distribution.
18547e1f66Speter *
19547e1f66Speter * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20547e1f66Speter * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21547e1f66Speter * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22547e1f66Speter * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23547e1f66Speter * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24547e1f66Speter * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25547e1f66Speter * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26547e1f66Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27547e1f66Speter * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28547e1f66Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29547e1f66Speter * POSSIBILITY OF SUCH DAMAGE.
30547e1f66Speter */
31547e1f66Speter
32547e1f66Speter /* Jornada 720 LCD screen driver. */
33547e1f66Speter
34547e1f66Speter #include <sys/cdefs.h>
35*4c494f76Srjs __KERNEL_RCSID(0, "$NetBSD: j720lcd.c,v 1.5 2009/05/29 14:15:45 rjs Exp $");
36547e1f66Speter
37547e1f66Speter #include <sys/param.h>
38547e1f66Speter #include <sys/systm.h>
39547e1f66Speter #include <sys/device.h>
40547e1f66Speter #include <sys/kernel.h>
41547e1f66Speter
42547e1f66Speter #include <machine/config_hook.h>
43547e1f66Speter #include <machine/platid.h>
44547e1f66Speter #include <machine/platid_mask.h>
45547e1f66Speter
46547e1f66Speter #include <arm/sa11x0/sa11x0_var.h>
47547e1f66Speter #include <arm/sa11x0/sa11x0_gpioreg.h>
48547e1f66Speter #include <arm/sa11x0/sa11x0_ppcreg.h>
49547e1f66Speter #include <arm/sa11x0/sa11x0_sspreg.h>
50547e1f66Speter
51547e1f66Speter #include <hpcarm/dev/j720sspvar.h>
52547e1f66Speter #include <hpcarm/dev/sed1356var.h>
53547e1f66Speter
54547e1f66Speter #ifdef DEBUG
55*4c494f76Srjs #define DPRINTF(arg) aprint_normal arg
56547e1f66Speter #else
57547e1f66Speter #define DPRINTF(arg) /* nothing */
58547e1f66Speter #endif
59547e1f66Speter
60547e1f66Speter struct j720lcd_softc {
61*4c494f76Srjs device_t sc_dev;
62547e1f66Speter
63547e1f66Speter struct j720ssp_softc *sc_ssp;
64547e1f66Speter };
65547e1f66Speter
66*4c494f76Srjs static int j720lcd_match(device_t, cfdata_t, void *);
67*4c494f76Srjs static void j720lcd_attach(device_t, device_t, void *);
68547e1f66Speter
69547e1f66Speter static int j720lcd_param(void *, int, long, void *);
70547e1f66Speter int j720lcd_power(void *, int, long, void *);
71547e1f66Speter
72*4c494f76Srjs CFATTACH_DECL_NEW(j720lcd, sizeof(struct j720lcd_softc),
73547e1f66Speter j720lcd_match, j720lcd_attach, NULL, NULL);
74547e1f66Speter
75547e1f66Speter
76547e1f66Speter static int
j720lcd_match(device_t parent,cfdata_t cf,void * aux)77*4c494f76Srjs j720lcd_match(device_t parent, cfdata_t cf, void *aux)
78547e1f66Speter {
79547e1f66Speter
80547e1f66Speter if (!platid_match(&platid, &platid_mask_MACH_HP_JORNADA_7XX))
81547e1f66Speter return 0;
82547e1f66Speter if (strcmp(cf->cf_name, "j720lcd") != 0)
83547e1f66Speter return 0;
84547e1f66Speter
85547e1f66Speter return 1;
86547e1f66Speter }
87547e1f66Speter
88547e1f66Speter static void
j720lcd_attach(device_t parent,device_t self,void * aux)89*4c494f76Srjs j720lcd_attach(device_t parent, device_t self, void *aux)
90547e1f66Speter {
91*4c494f76Srjs struct j720lcd_softc *sc = device_private(self);
92547e1f66Speter int brightness, contrast;
93547e1f66Speter
94*4c494f76Srjs sc->sc_dev = self;
95*4c494f76Srjs sc->sc_ssp = device_private(parent);
96547e1f66Speter
97547e1f66Speter /* LCD brightness hooks. */
98547e1f66Speter config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS,
99547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_param, sc);
100547e1f66Speter config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS,
101547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_param, sc);
102547e1f66Speter config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS_MAX,
103547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_param, sc);
104547e1f66Speter
105547e1f66Speter /* LCD contrast hooks. */
106547e1f66Speter config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST,
107547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_param, sc);
108547e1f66Speter config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST,
109547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_param, sc);
110547e1f66Speter config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST_MAX,
111547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_param, sc);
112547e1f66Speter
113547e1f66Speter /* LCD power hook. */
114547e1f66Speter #if 0
115547e1f66Speter config_hook(CONFIG_HOOK_POWERCONTROL,
116547e1f66Speter CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
117547e1f66Speter CONFIG_HOOK_SHARE, j720lcd_power, sc);
118547e1f66Speter #endif
119547e1f66Speter
120547e1f66Speter /* Get default brightness/contrast values. */
121547e1f66Speter config_hook_call(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS, &brightness);
122547e1f66Speter config_hook_call(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST, &contrast);
123547e1f66Speter
124*4c494f76Srjs aprint_normal(": brightness %d, contrast %d\n", brightness, contrast);
125547e1f66Speter }
126547e1f66Speter
127547e1f66Speter static int
j720lcd_param(void * ctx,int type,long id,void * msg)128547e1f66Speter j720lcd_param(void *ctx, int type, long id, void *msg)
129547e1f66Speter {
130547e1f66Speter struct j720lcd_softc *sc = ctx;
131547e1f66Speter struct j720ssp_softc *ssp = sc->sc_ssp;
132547e1f66Speter uint32_t data[2], len;
1337d389a2cSpeter const int maxval = 255;
134547e1f66Speter int i, s;
135547e1f66Speter
136547e1f66Speter switch (type) {
137547e1f66Speter case CONFIG_HOOK_GET:
138547e1f66Speter switch (id) {
139547e1f66Speter case CONFIG_HOOK_BRIGHTNESS_MAX:
140547e1f66Speter case CONFIG_HOOK_CONTRAST_MAX:
1417d389a2cSpeter *(int *)msg = maxval;
142547e1f66Speter return 1;
143547e1f66Speter case CONFIG_HOOK_BRIGHTNESS:
1440c9a60ffSpeter data[0] = 0xd6;
1450c9a60ffSpeter data[1] = 0x11;
146547e1f66Speter len = 2;
147547e1f66Speter break;
148547e1f66Speter case CONFIG_HOOK_CONTRAST:
1490c9a60ffSpeter data[0] = 0xd4;
1500c9a60ffSpeter data[1] = 0x11;
151547e1f66Speter len = 2;
152547e1f66Speter break;
153547e1f66Speter default:
154547e1f66Speter return 0;
155547e1f66Speter }
156547e1f66Speter break;
157547e1f66Speter
158547e1f66Speter case CONFIG_HOOK_SET:
159547e1f66Speter switch (id) {
160547e1f66Speter case CONFIG_HOOK_BRIGHTNESS:
161547e1f66Speter if (*(int *)msg >= 0) {
1620c9a60ffSpeter data[0] = 0xd3;
1637d389a2cSpeter data[1] = maxval - *(int *)msg;
164547e1f66Speter len = 2;
165547e1f66Speter } else {
166547e1f66Speter /* XXX hack */
1670c9a60ffSpeter data[0] = 0xdf;
168547e1f66Speter len = 1;
169547e1f66Speter }
170547e1f66Speter break;
171547e1f66Speter case CONFIG_HOOK_CONTRAST:
1720c9a60ffSpeter data[0] = 0xd1;
1737d389a2cSpeter data[1] = maxval - *(int *)msg;
174547e1f66Speter len = 2;
175547e1f66Speter break;
176547e1f66Speter default:
177547e1f66Speter return 0;
178547e1f66Speter }
179547e1f66Speter break;
180547e1f66Speter
181547e1f66Speter default:
182547e1f66Speter return 0;
183547e1f66Speter }
184547e1f66Speter
185547e1f66Speter s = splbio();
186547e1f66Speter bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PCR, 0x2000000);
187547e1f66Speter
188547e1f66Speter for (i = 0; i < len; i++) {
189547e1f66Speter if (j720ssp_readwrite(ssp, 1, data[i], &data[i], 500) < 0)
190547e1f66Speter goto out;
191547e1f66Speter }
192547e1f66Speter bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PSR, 0x2000000);
193547e1f66Speter splx(s);
194547e1f66Speter
195547e1f66Speter if (type == CONFIG_HOOK_SET)
196547e1f66Speter return 1;
197547e1f66Speter
1987d389a2cSpeter *(int *)msg = maxval - data[1];
199547e1f66Speter
200547e1f66Speter return 1;
201547e1f66Speter
202547e1f66Speter out:
203547e1f66Speter bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PSR, 0x2000000);
204547e1f66Speter
205547e1f66Speter /* reset SSP */
206547e1f66Speter bus_space_write_4(ssp->sc_iot, ssp->sc_ssph, SASSP_CR0, 0x307);
207547e1f66Speter delay(100);
208547e1f66Speter bus_space_write_4(ssp->sc_iot, ssp->sc_ssph, SASSP_CR0, 0x387);
209547e1f66Speter
210547e1f66Speter splx(s);
211547e1f66Speter
212547e1f66Speter DPRINTF(("j720lcd_param: error %x %x\n", data[0], data[1]));
213547e1f66Speter return 0;
214547e1f66Speter
215547e1f66Speter }
216547e1f66Speter
217547e1f66Speter int
j720lcd_power(void * ctx,int type,long id,void * msg)218547e1f66Speter j720lcd_power(void *ctx, int type, long id, void *msg)
219547e1f66Speter {
220547e1f66Speter struct sed1356_softc *sc = ctx;
221547e1f66Speter struct sa11x0_softc *psc = sc->sc_parent;
222547e1f66Speter uint32_t reg;
223547e1f66Speter int val;
224547e1f66Speter
225547e1f66Speter if (type != CONFIG_HOOK_POWERCONTROL ||
226547e1f66Speter id != CONFIG_HOOK_POWERCONTROL_LCDLIGHT)
227547e1f66Speter return 0;
228547e1f66Speter
229547e1f66Speter sed1356_init_brightness(sc, 0);
230547e1f66Speter sed1356_init_contrast(sc, 0);
231547e1f66Speter
232547e1f66Speter if (msg) {
233547e1f66Speter bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 0);
234547e1f66Speter
235547e1f66Speter reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
236547e1f66Speter reg |= 0x1;
237547e1f66Speter bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
238547e1f66Speter delay(50000);
239547e1f66Speter
240547e1f66Speter val = sc->sc_contrast;
241547e1f66Speter config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
242547e1f66Speter delay(100000);
243547e1f66Speter
244547e1f66Speter reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
245547e1f66Speter reg |= 0x4;
246547e1f66Speter bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
247547e1f66Speter
248547e1f66Speter val = sc->sc_brightness;
249547e1f66Speter config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
250547e1f66Speter
251547e1f66Speter reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
252547e1f66Speter reg |= 0x2;
253547e1f66Speter bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
254547e1f66Speter } else {
255547e1f66Speter reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
256547e1f66Speter reg &= ~0x2;
257547e1f66Speter bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
258547e1f66Speter reg &= ~0x4;
259547e1f66Speter bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
260547e1f66Speter delay(100000);
261547e1f66Speter
262547e1f66Speter val = -2;
263547e1f66Speter config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
264547e1f66Speter
265547e1f66Speter bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 1);
266547e1f66Speter
267547e1f66Speter delay(100000);
268547e1f66Speter reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
269547e1f66Speter reg &= ~0x1;
270547e1f66Speter bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
271547e1f66Speter }
272547e1f66Speter
273547e1f66Speter return 1;
274547e1f66Speter }
275