1/*
2 *
3 * Backlight driver for HP Jornada 700 series (710/720/728)
4 * Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 or any later version as published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/backlight.h>
13#include <linux/device.h>
14#include <linux/fb.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18
19#include <mach/jornada720.h>
20#include <mach/hardware.h>
21
22#include <video/s1d13xxxfb.h>
23
24#define BL_MAX_BRIGHT	255
25#define BL_DEF_BRIGHT	25
26
27static int jornada_bl_get_brightness(struct backlight_device *bd)
28{
29	int ret;
30
31	/* check if backlight is on */
32	if (!(PPSR & PPC_LDD1))
33		return 0;
34
35	jornada_ssp_start();
36
37	/* cmd should return txdummy */
38	ret = jornada_ssp_byte(GETBRIGHTNESS);
39
40	if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) {
41		printk(KERN_ERR "bl : get brightness timeout\n");
42		jornada_ssp_end();
43		return -ETIMEDOUT;
44	} else /* exchange txdummy for value */
45		ret = jornada_ssp_byte(TXDUMMY);
46
47	jornada_ssp_end();
48
49	return (BL_MAX_BRIGHT - ret);
50}
51
52static int jornada_bl_update_status(struct backlight_device *bd)
53{
54	int ret = 0;
55
56	jornada_ssp_start();
57
58	/* If backlight is off then really turn it off */
59	if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
60		ret = jornada_ssp_byte(BRIGHTNESSOFF);
61		if (ret != TXDUMMY) {
62			printk(KERN_INFO "bl : brightness off timeout\n");
63			/* turn off backlight */
64			PPSR &= ~PPC_LDD1;
65			PPDR |= PPC_LDD1;
66			ret = -ETIMEDOUT;
67		}
68	} else  /* turn on backlight */
69		PPSR |= PPC_LDD1;
70
71		/* send command to our mcu */
72		if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) {
73			printk(KERN_INFO "bl : failed to set brightness\n");
74			ret = -ETIMEDOUT;
75			goto out;
76		}
77
78		/* at this point we expect that the mcu has accepted
79		   our command and is waiting for our new value
80		   please note that maximum brightness is 255,
81		   but due to physical layout it is equal to 0, so we simply
82		   invert the value (MAX VALUE - NEW VALUE). */
83		if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) != TXDUMMY) {
84			printk(KERN_ERR "bl : set brightness failed\n");
85			ret = -ETIMEDOUT;
86		}
87
88		/* If infact we get an TXDUMMY as output we are happy and dont
89		   make any further comments about it */
90out:
91	jornada_ssp_end();
92
93	return ret;
94}
95
96static const struct backlight_ops jornada_bl_ops = {
97	.get_brightness = jornada_bl_get_brightness,
98	.update_status = jornada_bl_update_status,
99	.options = BL_CORE_SUSPENDRESUME,
100};
101
102static int jornada_bl_probe(struct platform_device *pdev)
103{
104	struct backlight_properties props;
105	int ret;
106	struct backlight_device *bd;
107
108	memset(&props, 0, sizeof(struct backlight_properties));
109	props.type = BACKLIGHT_RAW;
110	props.max_brightness = BL_MAX_BRIGHT;
111	bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL,
112				       &jornada_bl_ops, &props);
113
114	if (IS_ERR(bd)) {
115		ret = PTR_ERR(bd);
116		printk(KERN_ERR "bl : failed to register device, err=%x\n", ret);
117		return ret;
118	}
119
120	bd->props.power = FB_BLANK_UNBLANK;
121	bd->props.brightness = BL_DEF_BRIGHT;
122	/* note. make sure max brightness is set otherwise
123	   you will get seemingly non-related errors when
124	   trying to change brightness */
125	jornada_bl_update_status(bd);
126
127	platform_set_drvdata(pdev, bd);
128	printk(KERN_INFO "HP Jornada 700 series backlight driver\n");
129
130	return 0;
131}
132
133static int jornada_bl_remove(struct platform_device *pdev)
134{
135	struct backlight_device *bd = platform_get_drvdata(pdev);
136
137	backlight_device_unregister(bd);
138
139	return 0;
140}
141
142static struct platform_driver jornada_bl_driver = {
143	.probe		= jornada_bl_probe,
144	.remove		= jornada_bl_remove,
145	.driver	= {
146		.name	= "jornada_bl",
147	},
148};
149
150module_platform_driver(jornada_bl_driver);
151
152MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson>");
153MODULE_DESCRIPTION("HP Jornada 710/720/728 Backlight driver");
154MODULE_LICENSE("GPL");
155