tizen: Use unique directory prefix for baselibs packages
[platform/kernel/linux-rpi.git] / drivers / leds / leds-pca995x.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * LED driver for PCA995x I2C LED drivers
4  *
5  * Copyright 2011 bct electronic GmbH
6  * Copyright 2013 Qtechnology/AS
7  * Copyright 2022 NXP
8  * Copyright 2023 Marek Vasut
9  */
10
11 #include <linux/i2c.h>
12 #include <linux/leds.h>
13 #include <linux/module.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/property.h>
16 #include <linux/regmap.h>
17
18 /* Register definition */
19 #define PCA995X_MODE1                   0x00
20 #define PCA995X_MODE2                   0x01
21 #define PCA995X_LEDOUT0                 0x02
22 #define PCA9955B_PWM0                   0x08
23 #define PCA9952_PWM0                    0x0A
24 #define PCA9952_IREFALL                 0x43
25 #define PCA9955B_IREFALL                0x45
26
27 /* Auto-increment disabled. Normal mode */
28 #define PCA995X_MODE1_CFG               0x00
29
30 /* LED select registers determine the source that drives LED outputs */
31 #define PCA995X_LED_OFF                 0x0
32 #define PCA995X_LED_ON                  0x1
33 #define PCA995X_LED_PWM_MODE            0x2
34 #define PCA995X_LDRX_MASK               0x3
35 #define PCA995X_LDRX_BITS               2
36
37 #define PCA995X_MAX_OUTPUTS             16
38 #define PCA995X_OUTPUTS_PER_REG         4
39
40 #define PCA995X_IREFALL_FULL_CFG        0xFF
41 #define PCA995X_IREFALL_HALF_CFG        (PCA995X_IREFALL_FULL_CFG / 2)
42
43 #define PCA995X_TYPE_NON_B              0
44 #define PCA995X_TYPE_B                  1
45
46 #define ldev_to_led(c)  container_of(c, struct pca995x_led, ldev)
47
48 struct pca995x_led {
49         unsigned int led_no;
50         struct led_classdev ldev;
51         struct pca995x_chip *chip;
52 };
53
54 struct pca995x_chip {
55         struct regmap *regmap;
56         struct pca995x_led leds[PCA995X_MAX_OUTPUTS];
57         int btype;
58 };
59
60 static int pca995x_brightness_set(struct led_classdev *led_cdev,
61                                   enum led_brightness brightness)
62 {
63         struct pca995x_led *led = ldev_to_led(led_cdev);
64         struct pca995x_chip *chip = led->chip;
65         u8 ledout_addr, pwmout_addr;
66         int shift, ret;
67
68         pwmout_addr = (chip->btype ? PCA9955B_PWM0 : PCA9952_PWM0) + led->led_no;
69         ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG);
70         shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG);
71
72         switch (brightness) {
73         case LED_FULL:
74                 return regmap_update_bits(chip->regmap, ledout_addr,
75                                           PCA995X_LDRX_MASK << shift,
76                                           PCA995X_LED_ON << shift);
77         case LED_OFF:
78                 return regmap_update_bits(chip->regmap, ledout_addr,
79                                           PCA995X_LDRX_MASK << shift, 0);
80         default:
81                 /* Adjust brightness as per user input by changing individual PWM */
82                 ret = regmap_write(chip->regmap, pwmout_addr, brightness);
83                 if (ret)
84                         return ret;
85
86                 /*
87                  * Change LDRx configuration to individual brightness via PWM.
88                  * LED will stop blinking if it's doing so.
89                  */
90                 return regmap_update_bits(chip->regmap, ledout_addr,
91                                           PCA995X_LDRX_MASK << shift,
92                                           PCA995X_LED_PWM_MODE << shift);
93         }
94 }
95
96 static const struct regmap_config pca995x_regmap = {
97         .reg_bits = 8,
98         .val_bits = 8,
99         .max_register = 0x49,
100 };
101
102 static int pca995x_probe(struct i2c_client *client)
103 {
104         struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 };
105         struct fwnode_handle *np, *child;
106         struct device *dev = &client->dev;
107         struct pca995x_chip *chip;
108         struct pca995x_led *led;
109         int i, btype, reg, ret;
110
111         btype = (unsigned long)device_get_match_data(&client->dev);
112
113         np = dev_fwnode(dev);
114         if (!np)
115                 return -ENODEV;
116
117         chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
118         if (!chip)
119                 return -ENOMEM;
120
121         chip->btype = btype;
122         chip->regmap = devm_regmap_init_i2c(client, &pca995x_regmap);
123         if (IS_ERR(chip->regmap))
124                 return PTR_ERR(chip->regmap);
125
126         i2c_set_clientdata(client, chip);
127
128         fwnode_for_each_available_child_node(np, child) {
129                 ret = fwnode_property_read_u32(child, "reg", &reg);
130                 if (ret) {
131                         fwnode_handle_put(child);
132                         return ret;
133                 }
134
135                 if (reg < 0 || reg >= PCA995X_MAX_OUTPUTS || led_fwnodes[reg]) {
136                         fwnode_handle_put(child);
137                         return -EINVAL;
138                 }
139
140                 led = &chip->leds[reg];
141                 led_fwnodes[reg] = child;
142                 led->chip = chip;
143                 led->led_no = reg;
144                 led->ldev.brightness_set_blocking = pca995x_brightness_set;
145                 led->ldev.max_brightness = 255;
146         }
147
148         for (i = 0; i < PCA995X_MAX_OUTPUTS; i++) {
149                 struct led_init_data init_data = {};
150
151                 if (!led_fwnodes[i])
152                         continue;
153
154                 init_data.fwnode = led_fwnodes[i];
155
156                 ret = devm_led_classdev_register_ext(dev,
157                                                      &chip->leds[i].ldev,
158                                                      &init_data);
159                 if (ret < 0) {
160                         fwnode_handle_put(child);
161                         return dev_err_probe(dev, ret,
162                                              "Could not register LED %s\n",
163                                              chip->leds[i].ldev.name);
164                 }
165         }
166
167         /* Disable LED all-call address and set normal mode */
168         ret = regmap_write(chip->regmap, PCA995X_MODE1, PCA995X_MODE1_CFG);
169         if (ret)
170                 return ret;
171
172         /* IREF Output current value for all LEDn outputs */
173         return regmap_write(chip->regmap,
174                             btype ? PCA9955B_IREFALL : PCA9952_IREFALL,
175                             PCA995X_IREFALL_HALF_CFG);
176 }
177
178 static const struct i2c_device_id pca995x_id[] = {
179         { "pca9952", .driver_data = (kernel_ulong_t)PCA995X_TYPE_NON_B },
180         { "pca9955b", .driver_data = (kernel_ulong_t)PCA995X_TYPE_B },
181         {}
182 };
183 MODULE_DEVICE_TABLE(i2c, pca995x_id);
184
185 static const struct of_device_id pca995x_of_match[] = {
186         { .compatible = "nxp,pca9952",  .data = (void *)PCA995X_TYPE_NON_B },
187         { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B },
188         {},
189 };
190 MODULE_DEVICE_TABLE(of, pca995x_of_match);
191
192 static struct i2c_driver pca995x_driver = {
193         .driver = {
194                 .name = "leds-pca995x",
195                 .of_match_table = pca995x_of_match,
196         },
197         .probe = pca995x_probe,
198         .id_table = pca995x_id,
199 };
200 module_i2c_driver(pca995x_driver);
201
202 MODULE_AUTHOR("Isai Gaspar <isaiezequiel.gaspar@nxp.com>");
203 MODULE_DESCRIPTION("PCA995x LED driver");
204 MODULE_LICENSE("GPL");