1 /* $NetBSD: psh3lcd.c,v 1.2 2005/12/11 12:17:36 christos Exp $ */ 2 /* 3 * Copyright (c) 2005 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 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/device.h> 34 #include <sys/systm.h> 35 #include <sys/callout.h> 36 37 #include <machine/platid.h> 38 #include <machine/platid_mask.h> 39 40 #include <machine/config_hook.h> 41 42 #include <sh3/pfcreg.h> 43 #include <hpcsh/dev/hd64461/hd64461var.h> 44 #include <hpcsh/dev/hd64461/hd64461reg.h> 45 #include <hpcsh/dev/hd64461/hd64461gpioreg.h> 46 47 48 /* 49 * LCD contrast INC#: controlled by pin 0 in HD64461 GPIO port A. 50 * LCD contrast CS#: controlled by pin 1 in HD64461 GPIO port A. 51 * LCD contrast U/D#: controlled by pin 0 in SH7709 GPIO port D. 52 * 0 - down 53 * 1 - up 54 */ 55 #define PSH3LCD_CONTRAST_INC 0x01 56 #define PSH3LCD_CONTRAST_CS 0x02 57 #define PSH3LCD_CONTRAST_UD 0x01 58 59 /* 60 * LCD brightness: controled by HG71C105FE at AREA2. 61 * XXXX: That is custom IC. We don't know spec. X-< 62 */ 63 #define PSH3LCD_BRIGHTNESS_REG0 0xaa000072 64 #define PSH3LCD_BRIGHTNESS_REG1 0xaa000150 65 #define PSH3LCD_BRIGHTNESS_REG2 0xaa000152 66 67 /* brightness control data */ 68 static const struct psh3lcd_x0_bcd { /* 50PA, 30PA */ 69 uint8_t reg0; 70 uint8_t reg1; 71 uint8_t reg2; 72 } psh3lcd_x0_bcd[] = { 73 { 0x05, 0x08, 0x1e }, 74 { 0x05, 0x1d, 0x09 }, 75 { 0x04, 0x1e, 0x1e }, 76 { 0x06, 0x1e, 0x1e }, 77 { 0x07, 0x1e, 0x1e }, 78 { 0x00, 0x00, 0x00 } 79 }; 80 static const struct psh3lcd_xx0_bcd { /* 200JC */ 81 uint8_t reg1; 82 uint8_t reg2; 83 } psh3lcd_xx0_bcd[] = { 84 { 0x33, 0x0c }, 85 { 0x2d, 0x12 }, 86 { 0x26, 0x19 }, 87 { 0x20, 0x1f }, 88 { 0x1a, 0x25 }, 89 { 0x13, 0x2c }, 90 { 0x0d, 0x32 }, 91 { 0x07, 0x38 }, 92 { 0x01, 0x00 }, 93 { 0x00, 0x00 } 94 }; 95 96 #define PSH3LCD_XX0_BRIGHTNESS_MAX 8 97 #define PSH3LCD_X0_BRIGHTNESS_MAX 4 98 99 #define PSH3LCD_CONTRAST_MAX 2 /* XXX */ 100 #define PSH3LCD_CONTRAST 1 101 #define PSH3LCD_CONTRAST_UP 2 102 #define PSH3LCD_CONTRAST_DOWN 0 103 104 #define BCD_NO_MATCH (-1) 105 106 107 struct psh3lcd_softc { 108 struct device sc_dev; 109 int sc_brightness; 110 int sc_brightness_max; 111 void (*sc_set_brightness)(int); 112 }; 113 114 static int psh3lcd_match(struct device *, struct cfdata *, void *); 115 static void psh3lcd_attach(struct device *, struct device *, void *); 116 117 CFATTACH_DECL(psh3lcd, sizeof(struct psh3lcd_softc), 118 psh3lcd_match, psh3lcd_attach, NULL, NULL); 119 120 121 static inline int psh3lcd_x0_bcd_get(void); 122 static inline int psh3lcd_xx0_bcd_get(void); 123 static void psh3lcd_x0_set_brightness(int); 124 static void psh3lcd_xx0_set_brightness(int); 125 static void psh3lcd_set_contrast(int); 126 static int psh3lcd_param(void *, int, long, void *); 127 static int psh3lcd_power(void *, int, long, void *); 128 129 130 static inline int 131 psh3lcd_x0_bcd_get() 132 { 133 int i; 134 uint8_t bcr0, bcr1, bcr2; 135 136 bcr0 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG0); 137 bcr1 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG1); 138 bcr2 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG2); 139 140 for (i = 0; psh3lcd_x0_bcd[i].reg0 != 0; i++) 141 if (bcr0 == psh3lcd_x0_bcd[i].reg0 && 142 bcr1 == psh3lcd_x0_bcd[i].reg1 && 143 bcr2 == psh3lcd_x0_bcd[i].reg2) 144 break; 145 if (psh3lcd_x0_bcd[i].reg0 == 0) 146 return (BCD_NO_MATCH); 147 return (i); 148 } 149 150 static inline int 151 psh3lcd_xx0_bcd_get() 152 { 153 int i; 154 uint8_t bcr1, bcr2; 155 156 bcr1 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG1); 157 bcr2 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG2); 158 159 for (i = 0; psh3lcd_xx0_bcd[i].reg1 != 0; i++) 160 if (bcr1 == psh3lcd_xx0_bcd[i].reg1 && 161 bcr2 == psh3lcd_xx0_bcd[i].reg2) 162 break; 163 if (psh3lcd_xx0_bcd[i].reg1 == 0) 164 return (BCD_NO_MATCH); 165 return (i); 166 } 167 168 static void 169 psh3lcd_xx0_set_brightness(int index) 170 { 171 172 _reg_write_1(PSH3LCD_BRIGHTNESS_REG1, psh3lcd_xx0_bcd[index].reg1); 173 _reg_write_1(PSH3LCD_BRIGHTNESS_REG2, psh3lcd_xx0_bcd[index].reg2); 174 } 175 176 static void 177 psh3lcd_x0_set_brightness(int index) 178 { 179 180 _reg_write_1(PSH3LCD_BRIGHTNESS_REG0, psh3lcd_x0_bcd[index].reg0); 181 _reg_write_1(PSH3LCD_BRIGHTNESS_REG1, psh3lcd_x0_bcd[index].reg1); 182 _reg_write_1(PSH3LCD_BRIGHTNESS_REG2, psh3lcd_x0_bcd[index].reg2); 183 } 184 185 /* 186 * contrast control function. controlled by IC (X9313W). 187 */ 188 inline void 189 psh3lcd_set_contrast(int value) 190 { 191 uint16_t gpadr; 192 uint8_t pddr; 193 194 /* CS assert */ 195 gpadr = hd64461_reg_read_2(HD64461_GPADR_REG16); 196 gpadr &= ~PSH3LCD_CONTRAST_CS; 197 hd64461_reg_write_2(HD64461_GPADR_REG16, gpadr); 198 delay(1); 199 200 /* set U/D# */ 201 pddr = _reg_read_1(SH7709_PDDR); 202 if (value == PSH3LCD_CONTRAST_UP) 203 pddr |= PSH3LCD_CONTRAST_UD; 204 else if (value == PSH3LCD_CONTRAST_DOWN) 205 pddr &= ~PSH3LCD_CONTRAST_UD; 206 _reg_write_1(SH7709_PDDR, pddr); 207 delay(3); 208 209 /* INCrement */ 210 hd64461_reg_write_2(HD64461_GPADR_REG16, gpadr & ~PSH3LCD_CONTRAST_INC); 211 delay(1); 212 hd64461_reg_write_2(HD64461_GPADR_REG16, gpadr); 213 delay(1); 214 215 /* CS deassert */ 216 gpadr |= PSH3LCD_CONTRAST_CS; 217 hd64461_reg_write_2(HD64461_GPADR_REG16, gpadr); 218 delay(1); 219 } 220 221 static int 222 psh3lcd_match(struct device *parent, struct cfdata *cfp, void *aux) 223 { 224 uint8_t bcr0; 225 226 if (!platid_match(&platid, &platid_mask_MACH_HITACHI_PERSONA)) 227 return (0); 228 229 if (strcmp(cfp->cf_name, "psh3lcd") != 0) 230 return (0); 231 232 bcr0 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG0); 233 if (bcr0 == 0) { 234 if (psh3lcd_xx0_bcd_get() == BCD_NO_MATCH) 235 return (0); 236 } else { 237 if (psh3lcd_x0_bcd_get() == BCD_NO_MATCH) 238 return (0); 239 } 240 241 return (1); 242 } 243 244 static void 245 psh3lcd_attach(struct device *parent, struct device *self, void *aux) 246 { 247 struct psh3lcd_softc *sc = (struct psh3lcd_softc *)self; 248 uint8_t bcr0, bcr1, bcr2; 249 250 bcr0 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG0); 251 bcr1 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG1); 252 bcr2 = _reg_read_1(PSH3LCD_BRIGHTNESS_REG2); 253 if (bcr0 == 0) { 254 sc->sc_set_brightness = psh3lcd_xx0_set_brightness; 255 sc->sc_brightness = psh3lcd_xx0_bcd_get(); 256 sc->sc_brightness_max = PSH3LCD_XX0_BRIGHTNESS_MAX; 257 } else { 258 sc->sc_set_brightness = psh3lcd_x0_set_brightness; 259 sc->sc_brightness = psh3lcd_x0_bcd_get(); 260 sc->sc_brightness_max = PSH3LCD_X0_BRIGHTNESS_MAX; 261 } 262 printf(": brightness %d\n", sc->sc_brightness); 263 264 /* LCD contrast hooks */ 265 config_hook(CONFIG_HOOK_GET, 266 CONFIG_HOOK_CONTRAST_MAX, CONFIG_HOOK_SHARE, psh3lcd_param, sc); 267 config_hook(CONFIG_HOOK_GET, 268 CONFIG_HOOK_CONTRAST, CONFIG_HOOK_SHARE, psh3lcd_param, sc); 269 config_hook(CONFIG_HOOK_SET, 270 CONFIG_HOOK_CONTRAST, CONFIG_HOOK_SHARE, psh3lcd_param, sc); 271 272 /* LCD brightness hooks */ 273 config_hook(CONFIG_HOOK_GET, 274 CONFIG_HOOK_BRIGHTNESS_MAX, CONFIG_HOOK_SHARE, psh3lcd_param, sc); 275 config_hook(CONFIG_HOOK_GET, 276 CONFIG_HOOK_BRIGHTNESS, CONFIG_HOOK_SHARE, psh3lcd_param, sc); 277 config_hook(CONFIG_HOOK_SET, 278 CONFIG_HOOK_BRIGHTNESS, CONFIG_HOOK_SHARE, psh3lcd_param, sc); 279 280 /* LCD on/off hook */ 281 config_hook(CONFIG_HOOK_POWERCONTROL, 282 CONFIG_HOOK_POWERCONTROL_LCD, CONFIG_HOOK_SHARE, psh3lcd_power, sc); 283 } 284 285 286 static int 287 psh3lcd_param(void *ctx, int type, long id, void *msg) 288 { 289 struct psh3lcd_softc *sc = ctx; 290 int value; 291 292 switch (type) { 293 case CONFIG_HOOK_GET: 294 switch (id) { 295 case CONFIG_HOOK_CONTRAST: 296 *(int *)msg = PSH3LCD_CONTRAST; 297 return (0); 298 299 case CONFIG_HOOK_CONTRAST_MAX: 300 *(int *)msg = PSH3LCD_CONTRAST_MAX; 301 return (0); 302 303 case CONFIG_HOOK_BRIGHTNESS: 304 *(int *)msg = sc->sc_brightness; 305 return (0); 306 307 case CONFIG_HOOK_BRIGHTNESS_MAX: 308 *(int *)msg = sc->sc_brightness_max; 309 return (0); 310 } 311 break; 312 313 case CONFIG_HOOK_SET: 314 value = *(int *)msg; 315 316 switch (id) { 317 case CONFIG_HOOK_CONTRAST: 318 if (value != PSH3LCD_CONTRAST_UP && 319 value != PSH3LCD_CONTRAST_DOWN) 320 return (EINVAL); 321 psh3lcd_set_contrast(value); 322 return (0); 323 324 case CONFIG_HOOK_BRIGHTNESS: 325 if (value < 0) 326 value = 0; 327 if (value > sc->sc_brightness_max) 328 value = sc->sc_brightness_max; 329 sc->sc_brightness = value; 330 sc->sc_set_brightness(sc->sc_brightness); 331 return (0); 332 } 333 break; 334 } 335 336 return (EINVAL); 337 } 338 339 340 static int 341 psh3lcd_power(void *ctx, int type, long id, void *msg) 342 { 343 struct psh3lcd_softc *sc = ctx; 344 int on; 345 346 if (type != CONFIG_HOOK_POWERCONTROL || 347 id != CONFIG_HOOK_POWERCONTROL_LCD) 348 return (EINVAL); 349 350 on = (int)msg; 351 if (on) 352 sc->sc_set_brightness(sc->sc_brightness); 353 else 354 sc->sc_set_brightness(sc->sc_brightness_max + 1); 355 356 return (0); 357 } 358