1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // Copyright 2015 Texas Instruments
3*4882a593Smuzhiyun // Copyright 2018 Sebastian Reichel
4*4882a593Smuzhiyun // Copyright 2018 Pavel Machek <pavel@ucw.cz>
5*4882a593Smuzhiyun // TI LMU LED common framework, based on previous work from
6*4882a593Smuzhiyun // Milo Kim <milo.kim@ti.com>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/bitops.h>
9*4882a593Smuzhiyun #include <linux/err.h>
10*4882a593Smuzhiyun #include <linux/of_device.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/leds-ti-lmu-common.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun static const unsigned int ramp_table[16] = {2048, 262000, 524000, 1049000,
15*4882a593Smuzhiyun 2090000, 4194000, 8389000, 16780000, 33550000,
16*4882a593Smuzhiyun 41940000, 50330000, 58720000, 67110000,
17*4882a593Smuzhiyun 83880000, 100660000, 117440000};
18*4882a593Smuzhiyun
ti_lmu_common_update_brightness(struct ti_lmu_bank * lmu_bank,int brightness)19*4882a593Smuzhiyun static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank,
20*4882a593Smuzhiyun int brightness)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun struct regmap *regmap = lmu_bank->regmap;
23*4882a593Smuzhiyun u8 reg, val;
24*4882a593Smuzhiyun int ret;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun * Brightness register update
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * 11 bit dimming: update LSB bits and write MSB byte.
30*4882a593Smuzhiyun * MSB brightness should be shifted.
31*4882a593Smuzhiyun * 8 bit dimming: write MSB byte.
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun if (lmu_bank->max_brightness == MAX_BRIGHTNESS_11BIT) {
34*4882a593Smuzhiyun reg = lmu_bank->lsb_brightness_reg;
35*4882a593Smuzhiyun ret = regmap_update_bits(regmap, reg,
36*4882a593Smuzhiyun LMU_11BIT_LSB_MASK,
37*4882a593Smuzhiyun brightness);
38*4882a593Smuzhiyun if (ret)
39*4882a593Smuzhiyun return ret;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun val = brightness >> LMU_11BIT_MSB_SHIFT;
42*4882a593Smuzhiyun } else {
43*4882a593Smuzhiyun val = brightness;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun reg = lmu_bank->msb_brightness_reg;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun return regmap_write(regmap, reg, val);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
ti_lmu_common_set_brightness(struct ti_lmu_bank * lmu_bank,int brightness)51*4882a593Smuzhiyun int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun return ti_lmu_common_update_brightness(lmu_bank, brightness);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun EXPORT_SYMBOL(ti_lmu_common_set_brightness);
56*4882a593Smuzhiyun
ti_lmu_common_convert_ramp_to_index(unsigned int usec)57*4882a593Smuzhiyun static unsigned int ti_lmu_common_convert_ramp_to_index(unsigned int usec)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun int size = ARRAY_SIZE(ramp_table);
60*4882a593Smuzhiyun int i;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (usec <= ramp_table[0])
63*4882a593Smuzhiyun return 0;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (usec > ramp_table[size - 1])
66*4882a593Smuzhiyun return size - 1;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun for (i = 1; i < size; i++) {
69*4882a593Smuzhiyun if (usec == ramp_table[i])
70*4882a593Smuzhiyun return i;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* Find an approximate index by looking up the table */
73*4882a593Smuzhiyun if (usec > ramp_table[i - 1] && usec < ramp_table[i]) {
74*4882a593Smuzhiyun if (usec - ramp_table[i - 1] < ramp_table[i] - usec)
75*4882a593Smuzhiyun return i - 1;
76*4882a593Smuzhiyun else
77*4882a593Smuzhiyun return i;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
ti_lmu_common_set_ramp(struct ti_lmu_bank * lmu_bank)84*4882a593Smuzhiyun int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct regmap *regmap = lmu_bank->regmap;
87*4882a593Smuzhiyun u8 ramp, ramp_up, ramp_down;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (lmu_bank->ramp_up_usec == 0 && lmu_bank->ramp_down_usec == 0) {
90*4882a593Smuzhiyun ramp_up = 0;
91*4882a593Smuzhiyun ramp_down = 0;
92*4882a593Smuzhiyun } else {
93*4882a593Smuzhiyun ramp_up = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_up_usec);
94*4882a593Smuzhiyun ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun ramp = (ramp_up << 4) | ramp_down;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun EXPORT_SYMBOL(ti_lmu_common_set_ramp);
103*4882a593Smuzhiyun
ti_lmu_common_get_ramp_params(struct device * dev,struct fwnode_handle * child,struct ti_lmu_bank * lmu_data)104*4882a593Smuzhiyun int ti_lmu_common_get_ramp_params(struct device *dev,
105*4882a593Smuzhiyun struct fwnode_handle *child,
106*4882a593Smuzhiyun struct ti_lmu_bank *lmu_data)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun int ret;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun ret = fwnode_property_read_u32(child, "ramp-up-us",
111*4882a593Smuzhiyun &lmu_data->ramp_up_usec);
112*4882a593Smuzhiyun if (ret)
113*4882a593Smuzhiyun dev_warn(dev, "ramp-up-us property missing\n");
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun ret = fwnode_property_read_u32(child, "ramp-down-us",
117*4882a593Smuzhiyun &lmu_data->ramp_down_usec);
118*4882a593Smuzhiyun if (ret)
119*4882a593Smuzhiyun dev_warn(dev, "ramp-down-us property missing\n");
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun EXPORT_SYMBOL(ti_lmu_common_get_ramp_params);
124*4882a593Smuzhiyun
ti_lmu_common_get_brt_res(struct device * dev,struct fwnode_handle * child,struct ti_lmu_bank * lmu_data)125*4882a593Smuzhiyun int ti_lmu_common_get_brt_res(struct device *dev, struct fwnode_handle *child,
126*4882a593Smuzhiyun struct ti_lmu_bank *lmu_data)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun int ret;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun ret = device_property_read_u32(dev, "ti,brightness-resolution",
131*4882a593Smuzhiyun &lmu_data->max_brightness);
132*4882a593Smuzhiyun if (ret)
133*4882a593Smuzhiyun ret = fwnode_property_read_u32(child,
134*4882a593Smuzhiyun "ti,brightness-resolution",
135*4882a593Smuzhiyun &lmu_data->max_brightness);
136*4882a593Smuzhiyun if (lmu_data->max_brightness <= 0) {
137*4882a593Smuzhiyun lmu_data->max_brightness = MAX_BRIGHTNESS_8BIT;
138*4882a593Smuzhiyun return ret;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (lmu_data->max_brightness > MAX_BRIGHTNESS_11BIT)
142*4882a593Smuzhiyun lmu_data->max_brightness = MAX_BRIGHTNESS_11BIT;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun EXPORT_SYMBOL(ti_lmu_common_get_brt_res);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun MODULE_DESCRIPTION("TI LMU common LED framework");
150*4882a593Smuzhiyun MODULE_AUTHOR("Sebastian Reichel");
151*4882a593Smuzhiyun MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
152*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
153*4882a593Smuzhiyun MODULE_ALIAS("ti-lmu-led-common");
154