Blame view

drivers/leds/leds-lm3642.c 10.7 KB
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
  * Simple driver for Texas Instruments LM3642 LED Flash driver chip
  * Copyright (C) 2012 Texas Instruments
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
  */
  #include <linux/module.h>
  #include <linux/delay.h>
  #include <linux/i2c.h>
  #include <linux/leds.h>
  #include <linux/slab.h>
  #include <linux/platform_device.h>
  #include <linux/fs.h>
  #include <linux/regmap.h>
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  #include <linux/platform_data/leds-lm3642.h>
  
  #define	REG_FILT_TIME			(0x0)
  #define	REG_IVFM_MODE			(0x1)
  #define	REG_TORCH_TIME			(0x6)
  #define	REG_FLASH			(0x8)
  #define	REG_I_CTRL			(0x9)
  #define	REG_ENABLE			(0xA)
  #define	REG_FLAG			(0xB)
  #define	REG_MAX				(0xB)
  
  #define	UVLO_EN_SHIFT			(7)
  #define	IVM_D_TH_SHIFT			(2)
  #define	TORCH_RAMP_UP_TIME_SHIFT	(3)
  #define	TORCH_RAMP_DN_TIME_SHIFT	(0)
  #define	INDUCTOR_I_LIMIT_SHIFT		(6)
  #define	FLASH_RAMP_TIME_SHIFT		(3)
  #define	FLASH_TOUT_TIME_SHIFT		(0)
  #define	TORCH_I_SHIFT			(4)
  #define	FLASH_I_SHIFT			(0)
  #define	IVFM_SHIFT			(7)
  #define	TX_PIN_EN_SHIFT			(6)
  #define	STROBE_PIN_EN_SHIFT		(5)
  #define	TORCH_PIN_EN_SHIFT		(4)
  #define	MODE_BITS_SHIFT			(0)
  
  #define	UVLO_EN_MASK			(0x1)
  #define	IVM_D_TH_MASK			(0x7)
  #define	TORCH_RAMP_UP_TIME_MASK		(0x7)
  #define	TORCH_RAMP_DN_TIME_MASK		(0x7)
  #define	INDUCTOR_I_LIMIT_MASK		(0x1)
  #define	FLASH_RAMP_TIME_MASK		(0x7)
  #define	FLASH_TOUT_TIME_MASK		(0x7)
  #define	TORCH_I_MASK			(0x7)
  #define	FLASH_I_MASK			(0xF)
  #define	IVFM_MASK			(0x1)
  #define	TX_PIN_EN_MASK			(0x1)
  #define	STROBE_PIN_EN_MASK		(0x1)
  #define	TORCH_PIN_EN_MASK		(0x1)
  #define	MODE_BITS_MASK			(0x73)
  #define EX_PIN_CONTROL_MASK		(0x71)
  #define EX_PIN_ENABLE_MASK		(0x70)
  
  enum lm3642_mode {
  	MODES_STASNDBY = 0,
  	MODES_INDIC,
  	MODES_TORCH,
  	MODES_FLASH
  };
  
  struct lm3642_chip_data {
  	struct device *dev;
  
  	struct led_classdev cdev_flash;
  	struct led_classdev cdev_torch;
  	struct led_classdev cdev_indicator;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  	u8 br_flash;
  	u8 br_torch;
  	u8 br_indicator;
  
  	enum lm3642_torch_pin_enable torch_pin;
  	enum lm3642_strobe_pin_enable strobe_pin;
  	enum lm3642_tx_pin_enable tx_pin;
  
  	struct lm3642_platform_data *pdata;
  	struct regmap *regmap;
  	struct mutex lock;
  
  	unsigned int last_flag;
  };
  
  /* chip initialize */
98ea1ea20   Bill Pemberton   leds: remove use ...
90
  static int lm3642_chip_init(struct lm3642_chip_data *chip)
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
91
  {
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
92
93
94
95
  	int ret;
  	struct lm3642_platform_data *pdata = chip->pdata;
  
  	/* set enable register */
e76a322af   Axel Lin   leds: lm3642: Use...
96
97
  	ret = regmap_update_bits(chip->regmap, REG_ENABLE, EX_PIN_ENABLE_MASK,
  				 pdata->tx_pin);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
98
  	if (ret < 0)
e76a322af   Axel Lin   leds: lm3642: Use...
99
100
  		dev_err(chip->dev, "Failed to update REG_ENABLE Register
  ");
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  	return ret;
  }
  
  /* chip control */
  static int lm3642_control(struct lm3642_chip_data *chip,
  			  u8 brightness, enum lm3642_mode opmode)
  {
  	int ret;
  
  	ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read REG_FLAG Register
  ");
  		goto out;
  	}
  
  	if (chip->last_flag)
  		dev_info(chip->dev, "Last FLAG is 0x%x
  ", chip->last_flag);
  
  	/* brightness 0 means off-state */
  	if (!brightness)
  		opmode = MODES_STASNDBY;
  
  	switch (opmode) {
  	case MODES_TORCH:
  		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
  					 TORCH_I_MASK << TORCH_I_SHIFT,
  					 (brightness - 1) << TORCH_I_SHIFT);
  
  		if (chip->torch_pin)
  			opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
  		break;
  
  	case MODES_FLASH:
  		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
  					 FLASH_I_MASK << FLASH_I_SHIFT,
  					 (brightness - 1) << FLASH_I_SHIFT);
  
  		if (chip->strobe_pin)
  			opmode |= (STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT);
  		break;
  
  	case MODES_INDIC:
  		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
  					 TORCH_I_MASK << TORCH_I_SHIFT,
  					 (brightness - 1) << TORCH_I_SHIFT);
  		break;
  
  	case MODES_STASNDBY:
  
  		break;
  
  	default:
  		return ret;
  	}
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to write REG_I_CTRL Register
  ");
  		goto out;
  	}
  
  	if (chip->tx_pin)
  		opmode |= (TX_PIN_EN_MASK << TX_PIN_EN_SHIFT);
  
  	ret = regmap_update_bits(chip->regmap, REG_ENABLE,
  				 MODE_BITS_MASK << MODE_BITS_SHIFT,
  				 opmode << MODE_BITS_SHIFT);
  out:
  	return ret;
  }
  
  /* torch */
  
  /* torch pin config for lm3642*/
  static ssize_t lm3642_torch_pin_store(struct device *dev,
85b4b756f   Jingoo Han   leds: lm3642: ren...
177
  				      struct device_attribute *attr,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  				      const char *buf, size_t size)
  {
  	ssize_t ret;
  	struct led_classdev *led_cdev = dev_get_drvdata(dev);
  	struct lm3642_chip_data *chip =
  	    container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
  	unsigned int state;
  
  	ret = kstrtouint(buf, 10, &state);
  	if (ret)
  		goto out_strtoint;
  	if (state != 0)
  		state = 0x01 << TORCH_PIN_EN_SHIFT;
  
  	chip->torch_pin = state;
  	ret = regmap_update_bits(chip->regmap, REG_ENABLE,
  				 TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT,
  				 state);
  	if (ret < 0)
  		goto out;
  
  	return size;
  out:
  	dev_err(chip->dev, "%s:i2c access fail to register
  ", __func__);
eccb66385   Axel Lin   leds: lm3642: Ret...
203
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
204
205
206
  out_strtoint:
  	dev_err(chip->dev, "%s: fail to change str to int
  ", __func__);
eccb66385   Axel Lin   leds: lm3642: Ret...
207
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
208
  }
5cce0105c   Axel Lin   leds: lm3642: Fix...
209
  static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
210

bb58cc814   Andrew Lunn   leds: lm3642: Rem...
211
  static int lm3642_torch_brightness_set(struct led_classdev *cdev,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
212
213
214
215
  					enum led_brightness brightness)
  {
  	struct lm3642_chip_data *chip =
  	    container_of(cdev, struct lm3642_chip_data, cdev_torch);
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
216
  	int ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
217

bb58cc814   Andrew Lunn   leds: lm3642: Rem...
218
  	mutex_lock(&chip->lock);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
219
  	chip->br_torch = brightness;
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
220
221
222
  	ret = lm3642_control(chip, chip->br_torch, MODES_TORCH);
  	mutex_unlock(&chip->lock);
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
223
224
225
226
227
228
  }
  
  /* flash */
  
  /* strobe pin config for lm3642*/
  static ssize_t lm3642_strobe_pin_store(struct device *dev,
85b4b756f   Jingoo Han   leds: lm3642: ren...
229
  				       struct device_attribute *attr,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  				       const char *buf, size_t size)
  {
  	ssize_t ret;
  	struct led_classdev *led_cdev = dev_get_drvdata(dev);
  	struct lm3642_chip_data *chip =
  	    container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
  	unsigned int state;
  
  	ret = kstrtouint(buf, 10, &state);
  	if (ret)
  		goto out_strtoint;
  	if (state != 0)
  		state = 0x01 << STROBE_PIN_EN_SHIFT;
  
  	chip->strobe_pin = state;
  	ret = regmap_update_bits(chip->regmap, REG_ENABLE,
  				 STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT,
  				 state);
  	if (ret < 0)
  		goto out;
  
  	return size;
  out:
  	dev_err(chip->dev, "%s:i2c access fail to register
  ", __func__);
eccb66385   Axel Lin   leds: lm3642: Ret...
255
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
256
257
258
  out_strtoint:
  	dev_err(chip->dev, "%s: fail to change str to int
  ", __func__);
eccb66385   Axel Lin   leds: lm3642: Ret...
259
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
260
  }
5cce0105c   Axel Lin   leds: lm3642: Fix...
261
  static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
262

bb58cc814   Andrew Lunn   leds: lm3642: Rem...
263
  static int lm3642_strobe_brightness_set(struct led_classdev *cdev,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
264
265
266
267
  					 enum led_brightness brightness)
  {
  	struct lm3642_chip_data *chip =
  	    container_of(cdev, struct lm3642_chip_data, cdev_flash);
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
268
  	int ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
269
270
  
  	mutex_lock(&chip->lock);
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
271
272
  	chip->br_flash = brightness;
  	ret = lm3642_control(chip, chip->br_flash, MODES_FLASH);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
273
  	mutex_unlock(&chip->lock);
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
274
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
275
  }
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
276
277
  /* indicator */
  static int lm3642_indicator_brightness_set(struct led_classdev *cdev,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
278
279
280
281
  					    enum led_brightness brightness)
  {
  	struct lm3642_chip_data *chip =
  	    container_of(cdev, struct lm3642_chip_data, cdev_indicator);
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
282
  	int ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
283

bb58cc814   Andrew Lunn   leds: lm3642: Rem...
284
  	mutex_lock(&chip->lock);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
285
  	chip->br_indicator = brightness;
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
286
287
288
  	ret = lm3642_control(chip, chip->br_indicator, MODES_INDIC);
  	mutex_unlock(&chip->lock);
  	return ret;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
289
290
291
292
293
294
295
  }
  
  static const struct regmap_config lm3642_regmap = {
  	.reg_bits = 8,
  	.val_bits = 8,
  	.max_register = REG_MAX,
  };
fe29a3b0b   Johan Hovold   leds: lm3642: fix...
296
297
298
299
300
301
302
303
304
305
306
  static struct attribute *lm3642_flash_attrs[] = {
  	&dev_attr_strobe_pin.attr,
  	NULL
  };
  ATTRIBUTE_GROUPS(lm3642_flash);
  
  static struct attribute *lm3642_torch_attrs[] = {
  	&dev_attr_torch_pin.attr,
  	NULL
  };
  ATTRIBUTE_GROUPS(lm3642_torch);
98ea1ea20   Bill Pemberton   leds: remove use ...
307
  static int lm3642_probe(struct i2c_client *client,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
308
309
  				  const struct i2c_device_id *id)
  {
87aae1ea8   Jingoo Han   leds: use dev_get...
310
  	struct lm3642_platform_data *pdata = dev_get_platdata(&client->dev);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  	struct lm3642_chip_data *chip;
  
  	int err;
  
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  		dev_err(&client->dev, "i2c functionality check fail.
  ");
  		return -EOPNOTSUPP;
  	}
  
  	if (pdata == NULL) {
  		dev_err(&client->dev, "needs Platform Data.
  ");
  		return -ENODATA;
  	}
  
  	chip = devm_kzalloc(&client->dev,
  			    sizeof(struct lm3642_chip_data), GFP_KERNEL);
  	if (!chip)
  		return -ENOMEM;
  
  	chip->dev = &client->dev;
  	chip->pdata = pdata;
  
  	chip->tx_pin = pdata->tx_pin;
  	chip->torch_pin = pdata->torch_pin;
  	chip->strobe_pin = pdata->strobe_pin;
  
  	chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap);
  	if (IS_ERR(chip->regmap)) {
  		err = PTR_ERR(chip->regmap);
  		dev_err(&client->dev, "Failed to allocate register map: %d
  ",
  			err);
  		return err;
  	}
  
  	mutex_init(&chip->lock);
  	i2c_set_clientdata(client, chip);
  
  	err = lm3642_chip_init(chip);
  	if (err < 0)
  		goto err_out;
  
  	/* flash */
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
356
357
  	chip->cdev_flash.name = "flash";
  	chip->cdev_flash.max_brightness = 16;
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
358
  	chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set;
313bf0b1a   Kim, Milo   leds: lm355x, lm3...
359
  	chip->cdev_flash.default_trigger = "flash";
fe29a3b0b   Johan Hovold   leds: lm3642: fix...
360
  	chip->cdev_flash.groups = lm3642_flash_groups,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
361
362
363
364
365
366
367
  	err = led_classdev_register((struct device *)
  				    &client->dev, &chip->cdev_flash);
  	if (err < 0) {
  		dev_err(chip->dev, "failed to register flash
  ");
  		goto err_out;
  	}
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
368
369
  
  	/* torch */
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
370
371
  	chip->cdev_torch.name = "torch";
  	chip->cdev_torch.max_brightness = 8;
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
372
  	chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set;
313bf0b1a   Kim, Milo   leds: lm355x, lm3...
373
  	chip->cdev_torch.default_trigger = "torch";
fe29a3b0b   Johan Hovold   leds: lm3642: fix...
374
  	chip->cdev_torch.groups = lm3642_torch_groups,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
375
376
377
378
379
380
381
  	err = led_classdev_register((struct device *)
  				    &client->dev, &chip->cdev_torch);
  	if (err < 0) {
  		dev_err(chip->dev, "failed to register torch
  ");
  		goto err_create_torch_file;
  	}
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
382
383
  
  	/* indicator */
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
384
385
  	chip->cdev_indicator.name = "indicator";
  	chip->cdev_indicator.max_brightness = 8;
bb58cc814   Andrew Lunn   leds: lm3642: Rem...
386
387
  	chip->cdev_indicator.brightness_set_blocking =
  						lm3642_indicator_brightness_set;
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
388
389
390
391
392
393
394
395
396
397
398
399
400
  	err = led_classdev_register((struct device *)
  				    &client->dev, &chip->cdev_indicator);
  	if (err < 0) {
  		dev_err(chip->dev, "failed to register indicator
  ");
  		goto err_create_indicator_file;
  	}
  
  	dev_info(&client->dev, "LM3642 is initialized
  ");
  	return 0;
  
  err_create_indicator_file:
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
401
402
  	led_classdev_unregister(&chip->cdev_torch);
  err_create_torch_file:
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
403
404
405
406
  	led_classdev_unregister(&chip->cdev_flash);
  err_out:
  	return err;
  }
678e8a6be   Bill Pemberton   leds: remove use ...
407
  static int lm3642_remove(struct i2c_client *client)
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
408
409
410
411
  {
  	struct lm3642_chip_data *chip = i2c_get_clientdata(client);
  
  	led_classdev_unregister(&chip->cdev_indicator);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
412
  	led_classdev_unregister(&chip->cdev_torch);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
413
  	led_classdev_unregister(&chip->cdev_flash);
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  	regmap_write(chip->regmap, REG_ENABLE, 0);
  	return 0;
  }
  
  static const struct i2c_device_id lm3642_id[] = {
  	{LM3642_NAME, 0},
  	{}
  };
  
  MODULE_DEVICE_TABLE(i2c, lm3642_id);
  
  static struct i2c_driver lm3642_i2c_driver = {
  	.driver = {
  		   .name = LM3642_NAME,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
428
429
430
  		   .pm = NULL,
  		   },
  	.probe = lm3642_probe,
df07cf812   Bill Pemberton   leds: remove use ...
431
  	.remove = lm3642_remove,
8b7cfbec0   G.Shark Jeong   leds: Add new LED...
432
433
434
435
436
437
438
439
440
  	.id_table = lm3642_id,
  };
  
  module_i2c_driver(lm3642_i2c_driver);
  
  MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642");
  MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
  MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
  MODULE_LICENSE("GPL v2");