1 /* 2 * LED driver for TI lp3952 controller 3 * 4 * Copyright (C) 2016, DAQRI, LLC. 5 * Author: Tony Makkiel <tony.makkiel@daqri.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 */ 12 13 #include <linux/acpi.h> 14 #include <linux/delay.h> 15 #include <linux/gpio.h> 16 #include <linux/i2c.h> 17 #include <linux/io.h> 18 #include <linux/kernel.h> 19 #include <linux/leds.h> 20 #include <linux/leds-lp3952.h> 21 #include <linux/module.h> 22 #include <linux/notifier.h> 23 #include <linux/platform_device.h> 24 #include <linux/pm.h> 25 #include <linux/reboot.h> 26 #include <linux/regmap.h> 27 28 static int lp3952_register_write(struct i2c_client *client, u8 reg, u8 val) 29 { 30 int ret; 31 struct lp3952_led_array *priv = i2c_get_clientdata(client); 32 33 ret = regmap_write(priv->regmap, reg, val); 34 35 if (ret) 36 dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", 37 __func__, reg, val, ret); 38 return ret; 39 } 40 41 static void lp3952_on_off(struct lp3952_led_array *priv, 42 enum lp3952_leds led_id, bool on) 43 { 44 int ret, val; 45 46 dev_dbg(&priv->client->dev, "%s LED %d to %d\n", __func__, led_id, on); 47 48 val = 1 << led_id; 49 if (led_id == LP3952_LED_ALL) 50 val = LP3952_LED_MASK_ALL; 51 52 ret = regmap_update_bits(priv->regmap, LP3952_REG_LED_CTRL, val, 53 on ? val : 0); 54 if (ret) 55 dev_err(&priv->client->dev, "%s, Error %d\n", __func__, ret); 56 } 57 58 /* 59 * Using Imax to control brightness. There are 4 possible 60 * setting 25, 50, 75 and 100 % of Imax. Possible values are 61 * values 0-4. 0 meaning turn off. 62 */ 63 static int lp3952_set_brightness(struct led_classdev *cdev, 64 enum led_brightness value) 65 { 66 unsigned int reg, shift_val; 67 struct lp3952_ctrl_hdl *led = container_of(cdev, 68 struct lp3952_ctrl_hdl, 69 cdev); 70 struct lp3952_led_array *priv = (struct lp3952_led_array *)led->priv; 71 72 dev_dbg(cdev->dev, "Brightness request: %d on %d\n", value, 73 led->channel); 74 75 if (value == LED_OFF) { 76 lp3952_on_off(priv, led->channel, false); 77 return 0; 78 } 79 80 if (led->channel > LP3952_RED_1) { 81 dev_err(cdev->dev, " %s Invalid LED requested", __func__); 82 return -EINVAL; 83 } 84 85 if (led->channel >= LP3952_BLUE_1) { 86 reg = LP3952_REG_RGB1_MAX_I_CTRL; 87 shift_val = (led->channel - LP3952_BLUE_1) * 2; 88 } else { 89 reg = LP3952_REG_RGB2_MAX_I_CTRL; 90 shift_val = led->channel * 2; 91 } 92 93 /* Enable the LED in case it is not enabled already */ 94 lp3952_on_off(priv, led->channel, true); 95 96 return regmap_update_bits(priv->regmap, reg, 3 << shift_val, 97 --value << shift_val); 98 } 99 100 static int lp3952_get_label(struct device *dev, const char *label, char *dest) 101 { 102 int ret; 103 const char *str; 104 105 ret = device_property_read_string(dev, label, &str); 106 if (!ret) 107 strncpy(dest, str, LP3952_LABEL_MAX_LEN); 108 109 return ret; 110 } 111 112 static int lp3952_register_led_classdev(struct lp3952_led_array *priv) 113 { 114 int i, acpi_ret, ret = -ENODEV; 115 static const char *led_name_hdl[LP3952_LED_ALL] = { 116 "blue2", 117 "green2", 118 "red2", 119 "blue1", 120 "green1", 121 "red1" 122 }; 123 124 for (i = 0; i < LP3952_LED_ALL; i++) { 125 acpi_ret = lp3952_get_label(&priv->client->dev, led_name_hdl[i], 126 priv->leds[i].name); 127 if (acpi_ret) 128 continue; 129 130 priv->leds[i].cdev.name = priv->leds[i].name; 131 priv->leds[i].cdev.brightness = LED_OFF; 132 priv->leds[i].cdev.max_brightness = LP3952_BRIGHT_MAX; 133 priv->leds[i].cdev.brightness_set_blocking = 134 lp3952_set_brightness; 135 priv->leds[i].channel = i; 136 priv->leds[i].priv = priv; 137 138 ret = devm_led_classdev_register(&priv->client->dev, 139 &priv->leds[i].cdev); 140 if (ret < 0) { 141 dev_err(&priv->client->dev, 142 "couldn't register LED %s\n", 143 priv->leds[i].cdev.name); 144 break; 145 } 146 } 147 return ret; 148 } 149 150 static int lp3952_set_pattern_gen_cmd(struct lp3952_led_array *priv, 151 u8 cmd_index, u8 r, u8 g, u8 b, 152 enum lp3952_tt tt, enum lp3952_cet cet) 153 { 154 int ret; 155 struct ptrn_gen_cmd line = { 156 { 157 { 158 .r = r, 159 .g = g, 160 .b = b, 161 .cet = cet, 162 .tt = tt 163 } 164 } 165 }; 166 167 if (cmd_index >= LP3952_CMD_REG_COUNT) 168 return -EINVAL; 169 170 ret = lp3952_register_write(priv->client, 171 LP3952_REG_CMD_0 + cmd_index * 2, 172 line.bytes.msb); 173 if (ret) 174 return ret; 175 176 return lp3952_register_write(priv->client, 177 LP3952_REG_CMD_0 + cmd_index * 2 + 1, 178 line.bytes.lsb); 179 } 180 181 static int lp3952_configure(struct lp3952_led_array *priv) 182 { 183 int ret; 184 185 /* Disable any LEDs on from any previous conf. */ 186 ret = lp3952_register_write(priv->client, LP3952_REG_LED_CTRL, 0); 187 if (ret) 188 return ret; 189 190 /* enable rgb patter, loop */ 191 ret = lp3952_register_write(priv->client, LP3952_REG_PAT_GEN_CTRL, 192 LP3952_PATRN_LOOP | LP3952_PATRN_GEN_EN); 193 if (ret) 194 return ret; 195 196 /* Update Bit 6 (Active mode), Select both Led sets, Bit [1:0] */ 197 ret = lp3952_register_write(priv->client, LP3952_REG_ENABLES, 198 LP3952_ACTIVE_MODE | LP3952_INT_B00ST_LDR); 199 if (ret) 200 return ret; 201 202 /* Set Cmd1 for RGB intensity,cmd and transition time */ 203 return lp3952_set_pattern_gen_cmd(priv, 0, I46, I71, I100, TT0, 204 CET197); 205 } 206 207 static const struct regmap_config lp3952_regmap = { 208 .reg_bits = 8, 209 .val_bits = 8, 210 .max_register = REG_MAX, 211 .cache_type = REGCACHE_RBTREE, 212 }; 213 214 static int lp3952_probe(struct i2c_client *client, 215 const struct i2c_device_id *id) 216 { 217 int status; 218 struct lp3952_led_array *priv; 219 220 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 221 if (!priv) 222 return -ENOMEM; 223 224 priv->client = client; 225 226 priv->enable_gpio = devm_gpiod_get(&client->dev, "nrst", 227 GPIOD_OUT_HIGH); 228 if (IS_ERR(priv->enable_gpio)) { 229 status = PTR_ERR(priv->enable_gpio); 230 dev_err(&client->dev, "Failed to enable gpio: %d\n", status); 231 return status; 232 } 233 234 priv->regmap = devm_regmap_init_i2c(client, &lp3952_regmap); 235 if (IS_ERR(priv->regmap)) { 236 int err = PTR_ERR(priv->regmap); 237 238 dev_err(&client->dev, "Failed to allocate register map: %d\n", 239 err); 240 return err; 241 } 242 243 i2c_set_clientdata(client, priv); 244 245 status = lp3952_configure(priv); 246 if (status) { 247 dev_err(&client->dev, "Probe failed. Device not found (%d)\n", 248 status); 249 return status; 250 } 251 252 status = lp3952_register_led_classdev(priv); 253 if (status) { 254 dev_err(&client->dev, "Unable to register led_classdev: %d\n", 255 status); 256 return status; 257 } 258 259 return 0; 260 } 261 262 static int lp3952_remove(struct i2c_client *client) 263 { 264 struct lp3952_led_array *priv; 265 266 priv = i2c_get_clientdata(client); 267 lp3952_on_off(priv, LP3952_LED_ALL, false); 268 gpiod_set_value(priv->enable_gpio, 0); 269 270 return 0; 271 } 272 273 static const struct i2c_device_id lp3952_id[] = { 274 {LP3952_NAME, 0}, 275 {} 276 }; 277 MODULE_DEVICE_TABLE(i2c, lp3952_id); 278 279 #ifdef CONFIG_ACPI 280 static const struct acpi_device_id lp3952_acpi_match[] = { 281 {"TXNW3952", 0}, 282 {} 283 }; 284 285 MODULE_DEVICE_TABLE(acpi, lp3952_acpi_match); 286 #endif 287 288 static struct i2c_driver lp3952_i2c_driver = { 289 .driver = { 290 .name = LP3952_NAME, 291 .acpi_match_table = ACPI_PTR(lp3952_acpi_match), 292 }, 293 .probe = lp3952_probe, 294 .remove = lp3952_remove, 295 .id_table = lp3952_id, 296 }; 297 298 module_i2c_driver(lp3952_i2c_driver); 299 300 MODULE_AUTHOR("Tony Makkiel <tony.makkiel@daqri.com>"); 301 MODULE_DESCRIPTION("lp3952 I2C LED controller driver"); 302 MODULE_LICENSE("GPL v2"); 303