blob: a1a7397cbdc4444fd35c1a574c8d82612b55c4ff [file] [log] [blame]
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
7
8#include <backlight.h>
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +03009#include <dm.h>
Svyatoslav Ryhel98602962025-02-21 17:05:37 +020010#include <dm/ofnode.h>
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030011#include <i2c.h>
12#include <log.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15#include <asm/gpio.h>
16
17#define LM3533_BL_MIN_BRIGHTNESS 0x02
18#define LM3533_BL_MAX_BRIGHTNESS 0xFF
19
20#define LM3533_SINK_OUTPUT_CONFIG_1 0x10
21#define LM3533_CONTROL_BANK_A_PWM 0x14
22#define LM3533_CONTROL_BANK_AB_BRIGHTNESS 0x1A
23#define LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT 0x1F
24#define LM3533_CONTROL_BANK_ENABLE 0x27
25#define LM3533_OVP_FREQUENCY_PWM_POLARITY 0x2C
26#define LM3533_BRIGHTNESS_REGISTER_A 0x40
27
Svyatoslav Ryhel98602962025-02-21 17:05:37 +020028#define LM3533_BOOST_OVP_16V 16000000UL
29#define LM3533_BOOST_FREQ_500KHZ 500000UL
30
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030031struct lm3533_backlight_priv {
32 struct gpio_desc enable_gpio;
33 u32 def_bl_lvl;
Svyatoslav Ryhel98602962025-02-21 17:05:37 +020034
35 /* Core */
36 u32 boost_ovp;
37 u32 boost_freq;
38
39 /* Backlight */
40 u32 reg;
41 u16 max_current; /* 5000 - 29800 uA (800 uA step) */
42 u8 pwm; /* 0 - 0x3f */
43 bool linear;
44 bool hvled;
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030045};
46
47static int lm3533_backlight_enable(struct udevice *dev)
48{
49 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
50 int ret;
51
52 dm_gpio_set_value(&priv->enable_gpio, 1);
53 mdelay(5);
54
55 /* HVLED 1 & 2 are controlled by Bank A */
56 ret = dm_i2c_reg_write(dev, LM3533_SINK_OUTPUT_CONFIG_1, 0x00);
57 if (ret)
58 return ret;
59
60 /* PWM input is disabled for CABC */
61 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_PWM, 0x00);
62 if (ret)
63 return ret;
64
65 /* Linear & Control Bank A is configured for register Current control */
66 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS, 0x02);
67 if (ret)
68 return ret;
69
70 /* Full-Scale Current (20.2mA) */
71 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT, 0x13);
72 if (ret)
73 return ret;
74
75 /* Control Bank A is enable */
76 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_ENABLE, 0x01);
77 if (ret)
78 return ret;
79
80 ret = dm_i2c_reg_write(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY, 0x0A);
81 if (ret)
82 return ret;
83
84 return 0;
85}
86
87static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
88{
89 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
90 int ret;
91
92 if (percent == BACKLIGHT_DEFAULT)
93 percent = priv->def_bl_lvl;
94
95 if (percent < LM3533_BL_MIN_BRIGHTNESS)
96 percent = LM3533_BL_MIN_BRIGHTNESS;
97
98 if (percent > LM3533_BL_MAX_BRIGHTNESS)
99 percent = LM3533_BL_MAX_BRIGHTNESS;
100
101 /* Set brightness level */
102 ret = dm_i2c_reg_write(dev, LM3533_BRIGHTNESS_REGISTER_A,
103 percent);
104 if (ret)
105 return ret;
106
107 return 0;
108}
109
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200110static int lm3533_backlight_of_to_plat(struct udevice *dev)
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300111{
112 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200113 ofnode child;
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300114 int ret;
115
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300116 ret = gpio_request_by_name(dev, "enable-gpios", 0,
117 &priv->enable_gpio, GPIOD_IS_OUT);
118 if (ret) {
119 log_err("Could not decode enable-gpios (%d)\n", ret);
120 return ret;
121 }
122
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200123 priv->boost_ovp = dev_read_u32_default(dev, "ti,boost-ovp-microvolt",
124 LM3533_BOOST_OVP_16V);
125
126 /* boost_ovp is defined in microvolts, convert to enum value */
127 priv->boost_ovp = priv->boost_ovp / (8 * 1000 * 1000) - 2;
128
129 priv->boost_freq = dev_read_u32_default(dev, "ti,boost-freq-hz",
130 LM3533_BOOST_FREQ_500KHZ);
131
132 /* boost_freq is defined in Hz, convert to enum value */
133 priv->boost_freq = priv->boost_freq / (500 * 1000) - 1;
134
135 /* Backlight is one of children but has no dedicated driver */
136 ofnode_for_each_subnode(child, dev_ofnode(dev)) {
137 if (ofnode_device_is_compatible(child, "ti,lm3533-backlight")) {
138 const char *node_name = ofnode_get_name(child);
139
140 if (!strcmp(&node_name[10], "1"))
141 priv->reg = 1;
142 else
143 priv->reg = 0;
144
145 priv->max_current = ofnode_read_u32_default(child, "ti,max-current-microamp",
146 5000);
147 priv->pwm = ofnode_read_u32_default(child, "ti,pwm-config-mask", 0);
148
149 priv->def_bl_lvl = ofnode_read_u32_default(child, "default-brightness",
150 LM3533_BL_MAX_BRIGHTNESS);
151
152 priv->linear = ofnode_read_bool(child, "ti,linear-mapping-mode");
153 priv->hvled = ofnode_read_bool(child, "ti,hardware-controlled");
154 }
155 }
156
157 return 0;
158}
159
160static int lm3533_backlight_probe(struct udevice *dev)
161{
162 if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
163 return -EPROTONOSUPPORT;
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300164
165 return 0;
166}
167
168static const struct backlight_ops lm3533_backlight_ops = {
169 .enable = lm3533_backlight_enable,
170 .set_brightness = lm3533_backlight_set_brightness,
171};
172
173static const struct udevice_id lm3533_backlight_ids[] = {
174 { .compatible = "ti,lm3533" },
175 { }
176};
177
178U_BOOT_DRIVER(lm3533_backlight) = {
179 .name = "lm3533_backlight",
180 .id = UCLASS_PANEL_BACKLIGHT,
181 .of_match = lm3533_backlight_ids,
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200182 .of_to_plat = lm3533_backlight_of_to_plat,
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300183 .probe = lm3533_backlight_probe,
184 .ops = &lm3533_backlight_ops,
185 .priv_auto = sizeof(struct lm3533_backlight_priv),
186};