1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2025 Ion Agorria <ion@agorria.com>
4 */
5
6 #define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
7
8 #include <backlight.h>
9 #include <dm.h>
10 #include <i2c.h>
11 #include <log.h>
12 #include <linux/err.h>
13 #include <asm/gpio.h>
14 #include <power/regulator.h>
15
16 #define CMC623_I2C_REG_SELBANK 0x00
17 #define CMC623_I2C_REG_PWMCTRL 0xb4
18 #define CMC623_I2C_REG_REGMASK 0x28
19
20 #define CMC623_BL_MIN_BRIGHTNESS 0
21 #define CMC623_BL_DEF_BRIGHTNESS 50
22 #define CMC623_BL_MAX_BRIGHTNESS 100
23
24 struct cmc623_backlight_priv {
25 struct gpio_desc enable_gpio;
26 };
27
cmc623_backlight_enable(struct udevice * dev)28 static int cmc623_backlight_enable(struct udevice *dev)
29 {
30 struct cmc623_backlight_priv *priv = dev_get_priv(dev);
31
32 if (dm_gpio_is_valid(&priv->enable_gpio))
33 dm_gpio_set_value(&priv->enable_gpio, 1);
34
35 return 0;
36 }
37
cmc623_i2c_write(struct udevice * dev,u8 reg,u16 value)38 static int cmc623_i2c_write(struct udevice *dev, u8 reg, u16 value)
39 {
40 u8 data[2];
41
42 data[0] = (value >> 8) & 0xff;
43 data[1] = value & 0xff;
44
45 return dm_i2c_write(dev->parent, reg, data, 2);
46 }
47
cmc623_backlight_set_brightness(struct udevice * dev,int percent)48 static int cmc623_backlight_set_brightness(struct udevice *dev, int percent)
49 {
50 int ret;
51 u16 brightness;
52
53 if (percent == BACKLIGHT_DEFAULT)
54 percent = CMC623_BL_DEF_BRIGHTNESS;
55
56 if (percent < CMC623_BL_MIN_BRIGHTNESS)
57 percent = CMC623_BL_MIN_BRIGHTNESS;
58
59 if (percent > CMC623_BL_MAX_BRIGHTNESS)
60 percent = CMC623_BL_MAX_BRIGHTNESS;
61
62 brightness = 0x4000 | (percent << 4);
63
64 ret = cmc623_i2c_write(dev, CMC623_I2C_REG_SELBANK, 0x0000);
65 if (ret) {
66 log_debug("%s: error at CMC623_I2C_REG_SELBANK (%d)\n",
67 __func__, ret);
68 return ret;
69 }
70
71 ret = cmc623_i2c_write(dev, CMC623_I2C_REG_PWMCTRL, brightness);
72 if (ret) {
73 log_debug("%s: error at CMC623_I2C_REG_PWMCTRL (%d)\n",
74 __func__, ret);
75 return ret;
76 }
77
78 ret = cmc623_i2c_write(dev, CMC623_I2C_REG_REGMASK, 0x0000);
79 if (ret) {
80 log_debug("%s: error at CMC623_I2C_REG_REGMASK (%d)\n",
81 __func__, ret);
82 return ret;
83 }
84
85 return 0;
86 }
87
cmc623_backlight_of_to_plat(struct udevice * dev)88 static int cmc623_backlight_of_to_plat(struct udevice *dev)
89 {
90 struct cmc623_backlight_priv *priv = dev_get_priv(dev);
91
92 gpio_request_by_name(dev, "enable-gpios", 0,
93 &priv->enable_gpio, GPIOD_IS_OUT);
94
95 return 0;
96 }
97
cmc623_backlight_probe(struct udevice * dev)98 static int cmc623_backlight_probe(struct udevice *dev)
99 {
100 if (device_get_uclass_id(dev->parent) != UCLASS_VIDEO_BRIDGE)
101 return -EPROTONOSUPPORT;
102
103 return 0;
104 }
105
106 static const struct backlight_ops cmc623_backlight_ops = {
107 .enable = cmc623_backlight_enable,
108 .set_brightness = cmc623_backlight_set_brightness,
109 };
110
111 static const struct udevice_id cmc623_backlight_ids[] = {
112 { .compatible = "samsung,cmc623-backlight" },
113 { }
114 };
115
116 U_BOOT_DRIVER(cmc623_backlight) = {
117 .name = "cmc623_backlight",
118 .id = UCLASS_PANEL_BACKLIGHT,
119 .of_match = cmc623_backlight_ids,
120 .of_to_plat = cmc623_backlight_of_to_plat,
121 .probe = cmc623_backlight_probe,
122 .ops = &cmc623_backlight_ops,
123 .priv_auto = sizeof(struct cmc623_backlight_priv),
124 };
125