1 // SPDX-License-Identifier: GPL-2.0-only
3 * linux/drivers/video/backlight/aat2870_bl.c
5 * Copyright (c) 2011, NVIDIA Corporation.
6 * Author: Jin Park <jinyoungp@nvidia.com>
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/platform_device.h>
13 #include <linux/mutex.h>
14 #include <linux/delay.h>
16 #include <linux/backlight.h>
17 #include <linux/mfd/aat2870.h>
19 struct aat2870_bl_driver_data
{
20 struct platform_device
*pdev
;
21 struct backlight_device
*bd
;
25 int brightness
; /* current brightness */
28 static inline int aat2870_brightness(struct aat2870_bl_driver_data
*aat2870_bl
,
31 struct backlight_device
*bd
= aat2870_bl
->bd
;
34 val
= brightness
* (aat2870_bl
->max_current
- 1);
35 val
/= bd
->props
.max_brightness
;
40 static inline int aat2870_bl_enable(struct aat2870_bl_driver_data
*aat2870_bl
)
42 struct aat2870_data
*aat2870
43 = dev_get_drvdata(aat2870_bl
->pdev
->dev
.parent
);
45 return aat2870
->write(aat2870
, AAT2870_BL_CH_EN
,
46 (u8
)aat2870_bl
->channels
);
49 static inline int aat2870_bl_disable(struct aat2870_bl_driver_data
*aat2870_bl
)
51 struct aat2870_data
*aat2870
52 = dev_get_drvdata(aat2870_bl
->pdev
->dev
.parent
);
54 return aat2870
->write(aat2870
, AAT2870_BL_CH_EN
, 0x0);
57 static int aat2870_bl_update_status(struct backlight_device
*bd
)
59 struct aat2870_bl_driver_data
*aat2870_bl
= bl_get_data(bd
);
60 struct aat2870_data
*aat2870
=
61 dev_get_drvdata(aat2870_bl
->pdev
->dev
.parent
);
62 int brightness
= bd
->props
.brightness
;
65 if ((brightness
< 0) || (bd
->props
.max_brightness
< brightness
)) {
66 dev_err(&bd
->dev
, "invalid brightness, %d\n", brightness
);
70 dev_dbg(&bd
->dev
, "brightness=%d, power=%d, state=%d\n",
71 bd
->props
.brightness
, bd
->props
.power
, bd
->props
.state
);
73 if ((bd
->props
.power
!= FB_BLANK_UNBLANK
) ||
74 (bd
->props
.state
& BL_CORE_FBBLANK
) ||
75 (bd
->props
.state
& BL_CORE_SUSPENDED
))
78 ret
= aat2870
->write(aat2870
, AAT2870_BLM
,
79 (u8
)aat2870_brightness(aat2870_bl
, brightness
));
83 if (brightness
== 0) {
84 ret
= aat2870_bl_disable(aat2870_bl
);
87 } else if (aat2870_bl
->brightness
== 0) {
88 ret
= aat2870_bl_enable(aat2870_bl
);
93 aat2870_bl
->brightness
= brightness
;
98 static int aat2870_bl_check_fb(struct backlight_device
*bd
, struct fb_info
*fi
)
103 static const struct backlight_ops aat2870_bl_ops
= {
104 .options
= BL_CORE_SUSPENDRESUME
,
105 .update_status
= aat2870_bl_update_status
,
106 .check_fb
= aat2870_bl_check_fb
,
109 static int aat2870_bl_probe(struct platform_device
*pdev
)
111 struct aat2870_bl_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
112 struct aat2870_bl_driver_data
*aat2870_bl
;
113 struct backlight_device
*bd
;
114 struct backlight_properties props
;
118 dev_err(&pdev
->dev
, "No platform data\n");
123 if (pdev
->id
!= AAT2870_ID_BL
) {
124 dev_err(&pdev
->dev
, "Invalid device ID, %d\n", pdev
->id
);
129 aat2870_bl
= devm_kzalloc(&pdev
->dev
,
130 sizeof(struct aat2870_bl_driver_data
),
137 memset(&props
, 0, sizeof(struct backlight_properties
));
139 props
.type
= BACKLIGHT_RAW
;
140 bd
= devm_backlight_device_register(&pdev
->dev
, "aat2870-backlight",
141 &pdev
->dev
, aat2870_bl
, &aat2870_bl_ops
,
145 "Failed allocate memory for backlight device\n");
150 aat2870_bl
->pdev
= pdev
;
151 platform_set_drvdata(pdev
, aat2870_bl
);
155 if (pdata
->channels
> 0)
156 aat2870_bl
->channels
= pdata
->channels
;
158 aat2870_bl
->channels
= AAT2870_BL_CH_ALL
;
160 if (pdata
->max_current
> 0)
161 aat2870_bl
->max_current
= pdata
->max_current
;
163 aat2870_bl
->max_current
= AAT2870_CURRENT_27_9
;
165 if (pdata
->max_brightness
> 0)
166 bd
->props
.max_brightness
= pdata
->max_brightness
;
168 bd
->props
.max_brightness
= 255;
170 aat2870_bl
->brightness
= 0;
171 bd
->props
.power
= FB_BLANK_UNBLANK
;
172 bd
->props
.brightness
= bd
->props
.max_brightness
;
174 ret
= aat2870_bl_update_status(bd
);
176 dev_err(&pdev
->dev
, "Failed to initialize\n");
186 static int aat2870_bl_remove(struct platform_device
*pdev
)
188 struct aat2870_bl_driver_data
*aat2870_bl
= platform_get_drvdata(pdev
);
189 struct backlight_device
*bd
= aat2870_bl
->bd
;
191 bd
->props
.power
= FB_BLANK_POWERDOWN
;
192 bd
->props
.brightness
= 0;
193 backlight_update_status(bd
);
198 static struct platform_driver aat2870_bl_driver
= {
200 .name
= "aat2870-backlight",
202 .probe
= aat2870_bl_probe
,
203 .remove
= aat2870_bl_remove
,
206 static int __init
aat2870_bl_init(void)
208 return platform_driver_register(&aat2870_bl_driver
);
210 subsys_initcall(aat2870_bl_init
);
212 static void __exit
aat2870_bl_exit(void)
214 platform_driver_unregister(&aat2870_bl_driver
);
216 module_exit(aat2870_bl_exit
);
218 MODULE_DESCRIPTION("AnalogicTech AAT2870 Backlight");
219 MODULE_LICENSE("GPL");
220 MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");