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