1 // SPDX-License-Identifier: GPL-2.0-only
4 * https://www.kinet-ic.com/uploads/web/KTD2801/KTD2801-04b.pdf
6 #include <linux/backlight.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/leds-expresswire.h>
9 #include <linux/platform_device.h>
10 #include <linux/property.h>
12 #define KTD2801_DEFAULT_BRIGHTNESS 100
13 #define KTD2801_MAX_BRIGHTNESS 255
15 /* These values have been extracted from Samsung's driver. */
16 static const struct expresswire_timing ktd2801_timing
= {
18 .detect_delay_us
= 150,
23 .end_of_data_low_us
= 10,
24 .end_of_data_high_us
= 350
27 struct ktd2801_backlight
{
28 struct expresswire_common_props props
;
29 struct backlight_device
*bd
;
33 static int ktd2801_update_status(struct backlight_device
*bd
)
35 struct ktd2801_backlight
*ktd2801
= bl_get_data(bd
);
36 u8 brightness
= (u8
) backlight_get_brightness(bd
);
38 if (backlight_is_blank(bd
)) {
39 expresswire_power_off(&ktd2801
->props
);
40 ktd2801
->was_on
= false;
44 if (!ktd2801
->was_on
) {
45 expresswire_enable(&ktd2801
->props
);
46 ktd2801
->was_on
= true;
49 expresswire_write_u8(&ktd2801
->props
, brightness
);
54 static const struct backlight_ops ktd2801_backlight_ops
= {
55 .update_status
= ktd2801_update_status
,
58 static int ktd2801_backlight_probe(struct platform_device
*pdev
)
60 struct device
*dev
= &pdev
->dev
;
61 struct backlight_device
*bd
;
62 struct ktd2801_backlight
*ktd2801
;
63 u32 brightness
, max_brightness
;
66 ktd2801
= devm_kzalloc(dev
, sizeof(*ktd2801
), GFP_KERNEL
);
69 ktd2801
->was_on
= true;
70 ktd2801
->props
.timing
= ktd2801_timing
;
72 ret
= device_property_read_u32(dev
, "max-brightness", &max_brightness
);
74 max_brightness
= KTD2801_MAX_BRIGHTNESS
;
75 if (max_brightness
> KTD2801_MAX_BRIGHTNESS
) {
76 dev_err(dev
, "illegal max brightness specified\n");
77 max_brightness
= KTD2801_MAX_BRIGHTNESS
;
80 ret
= device_property_read_u32(dev
, "default-brightness", &brightness
);
82 brightness
= KTD2801_DEFAULT_BRIGHTNESS
;
83 if (brightness
> max_brightness
) {
84 dev_err(dev
, "default brightness exceeds max\n");
85 brightness
= max_brightness
;
88 ktd2801
->props
.ctrl_gpio
= devm_gpiod_get(dev
, "ctrl", GPIOD_OUT_HIGH
);
89 if (IS_ERR(ktd2801
->props
.ctrl_gpio
))
90 return dev_err_probe(dev
, PTR_ERR(ktd2801
->props
.ctrl_gpio
),
91 "failed to get backlight GPIO");
92 gpiod_set_consumer_name(ktd2801
->props
.ctrl_gpio
, dev_name(dev
));
94 bd
= devm_backlight_device_register(dev
, dev_name(dev
), dev
, ktd2801
,
95 &ktd2801_backlight_ops
, NULL
);
97 return dev_err_probe(dev
, PTR_ERR(bd
),
98 "failed to register backlight");
100 bd
->props
.max_brightness
= max_brightness
;
101 bd
->props
.brightness
= brightness
;
104 platform_set_drvdata(pdev
, bd
);
105 backlight_update_status(bd
);
110 static const struct of_device_id ktd2801_of_match
[] = {
111 { .compatible
= "kinetic,ktd2801" },
114 MODULE_DEVICE_TABLE(of
, ktd2801_of_match
);
116 static struct platform_driver ktd2801_backlight_driver
= {
118 .name
= "ktd2801-backlight",
119 .of_match_table
= ktd2801_of_match
,
121 .probe
= ktd2801_backlight_probe
,
123 module_platform_driver(ktd2801_backlight_driver
);
125 MODULE_IMPORT_NS(EXPRESSWIRE
);
126 MODULE_AUTHOR("Duje Mihanović <duje.mihanovic@skole.hr>");
127 MODULE_DESCRIPTION("Kinetic KTD2801 Backlight Driver");
128 MODULE_LICENSE("GPL");