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