Blame view

drivers/leds/leds-lt3593.c 4.35 KB
a8dd18feb   Daniel Mack   leds: Add driver ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   * LEDs driver for LT3593 controllers
   *
   * See the datasheet at http://cds.linear.com/docs/Datasheet/3593f.pdf
   *
   * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
   *
   * Based on leds-gpio.c,
   *
   *   Copyright (C) 2007 8D Technologies inc.
   *   Raphael Assenat <raph@8d.com>
   *   Copyright (C) 2008 Freescale Semiconductor, Inc.
   *
   * 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/kernel.h>
a8dd18feb   Daniel Mack   leds: Add driver ...
20
21
  #include <linux/platform_device.h>
  #include <linux/leds.h>
a8dd18feb   Daniel Mack   leds: Add driver ...
22
23
  #include <linux/delay.h>
  #include <linux/gpio.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/slab.h>
54f4dedb5   Paul Gortmaker   drivers/leds: Add...
25
  #include <linux/module.h>
a8dd18feb   Daniel Mack   leds: Add driver ...
26
27
28
29
  
  struct lt3593_led_data {
  	struct led_classdev cdev;
  	unsigned gpio;
a8dd18feb   Daniel Mack   leds: Add driver ...
30
  };
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
31
32
  static int lt3593_led_set(struct led_classdev *led_cdev,
  			   enum led_brightness value)
a8dd18feb   Daniel Mack   leds: Add driver ...
33
  {
a8dd18feb   Daniel Mack   leds: Add driver ...
34
  	struct lt3593_led_data *led_dat =
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
35
36
  		container_of(led_cdev, struct lt3593_led_data, cdev);
  	int pulses;
a8dd18feb   Daniel Mack   leds: Add driver ...
37
38
39
40
41
42
43
44
45
  
  	/*
  	 * The LT3593 resets its internal current level register to the maximum
  	 * level on the first falling edge on the control pin. Each following
  	 * falling edge decreases the current level by 625uA. Up to 32 pulses
  	 * can be sent, so the maximum power reduction is 20mA.
  	 * After a timeout of 128us, the value is taken from the register and
  	 * applied is to the output driver.
  	 */
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
46
  	if (value == 0) {
a8dd18feb   Daniel Mack   leds: Add driver ...
47
  		gpio_set_value_cansleep(led_dat->gpio, 0);
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
48
  		return 0;
a8dd18feb   Daniel Mack   leds: Add driver ...
49
  	}
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
50
  	pulses = 32 - (value * 32) / 255;
a8dd18feb   Daniel Mack   leds: Add driver ...
51
52
53
54
55
  
  	if (pulses == 0) {
  		gpio_set_value_cansleep(led_dat->gpio, 0);
  		mdelay(1);
  		gpio_set_value_cansleep(led_dat->gpio, 1);
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
56
  		return 0;
a8dd18feb   Daniel Mack   leds: Add driver ...
57
58
59
60
61
62
63
64
65
66
  	}
  
  	gpio_set_value_cansleep(led_dat->gpio, 1);
  
  	while (pulses--) {
  		gpio_set_value_cansleep(led_dat->gpio, 0);
  		udelay(1);
  		gpio_set_value_cansleep(led_dat->gpio, 1);
  		udelay(1);
  	}
a8dd18feb   Daniel Mack   leds: Add driver ...
67

a0011f1be   Andrew Lunn   leds: lt3593: Rem...
68
  	return 0;
a8dd18feb   Daniel Mack   leds: Add driver ...
69
  }
98ea1ea20   Bill Pemberton   leds: remove use ...
70
  static int create_lt3593_led(const struct gpio_led *template,
a8dd18feb   Daniel Mack   leds: Add driver ...
71
72
73
74
75
76
  	struct lt3593_led_data *led_dat, struct device *parent)
  {
  	int ret, state;
  
  	/* skip leds on GPIOs that aren't available */
  	if (!gpio_is_valid(template->gpio)) {
30e5c3e6b   Sachin Kamat   leds: leds-lt3593...
77
78
  		dev_info(parent, "%s: skipping unavailable LT3593 LED at gpio %d (%s)
  ",
a8dd18feb   Daniel Mack   leds: Add driver ...
79
80
81
  				KBUILD_MODNAME, template->gpio, template->name);
  		return 0;
  	}
a8dd18feb   Daniel Mack   leds: Add driver ...
82
83
84
  	led_dat->cdev.name = template->name;
  	led_dat->cdev.default_trigger = template->default_trigger;
  	led_dat->gpio = template->gpio;
a0011f1be   Andrew Lunn   leds: lt3593: Rem...
85
  	led_dat->cdev.brightness_set_blocking = lt3593_led_set;
a8dd18feb   Daniel Mack   leds: Add driver ...
86
87
88
89
90
91
  
  	state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
  	led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
  
  	if (!template->retain_state_suspended)
  		led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
84f6942cd   Jingoo Han   leds: leds-lt3593...
92
93
94
  	ret = devm_gpio_request_one(parent, template->gpio, state ?
  				    GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
  				    template->name);
a8dd18feb   Daniel Mack   leds: Add driver ...
95
  	if (ret < 0)
507d967bc   Jingoo Han   leds: leds-lt3593...
96
  		return ret;
a8dd18feb   Daniel Mack   leds: Add driver ...
97

a8dd18feb   Daniel Mack   leds: Add driver ...
98
99
  	ret = led_classdev_register(parent, &led_dat->cdev);
  	if (ret < 0)
95a8ff835   Sachin Kamat   leds: leds-lt3593...
100
  		return ret;
a8dd18feb   Daniel Mack   leds: Add driver ...
101

30e5c3e6b   Sachin Kamat   leds: leds-lt3593...
102
103
  	dev_info(parent, "%s: registered LT3593 LED '%s' at GPIO %d
  ",
a8dd18feb   Daniel Mack   leds: Add driver ...
104
105
106
  		KBUILD_MODNAME, template->name, template->gpio);
  
  	return 0;
a8dd18feb   Daniel Mack   leds: Add driver ...
107
108
109
110
111
112
113
114
  }
  
  static void delete_lt3593_led(struct lt3593_led_data *led)
  {
  	if (!gpio_is_valid(led->gpio))
  		return;
  
  	led_classdev_unregister(&led->cdev);
a8dd18feb   Daniel Mack   leds: Add driver ...
115
  }
98ea1ea20   Bill Pemberton   leds: remove use ...
116
  static int lt3593_led_probe(struct platform_device *pdev)
a8dd18feb   Daniel Mack   leds: Add driver ...
117
  {
87aae1ea8   Jingoo Han   leds: use dev_get...
118
  	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
a8dd18feb   Daniel Mack   leds: Add driver ...
119
120
121
122
123
  	struct lt3593_led_data *leds_data;
  	int i, ret = 0;
  
  	if (!pdata)
  		return -EBUSY;
0a8d9d4a6   Bryan Wu   leds: convert LT3...
124
125
126
  	leds_data = devm_kzalloc(&pdev->dev,
  			sizeof(struct lt3593_led_data) * pdata->num_leds,
  			GFP_KERNEL);
a8dd18feb   Daniel Mack   leds: Add driver ...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  	if (!leds_data)
  		return -ENOMEM;
  
  	for (i = 0; i < pdata->num_leds; i++) {
  		ret = create_lt3593_led(&pdata->leds[i], &leds_data[i],
  				      &pdev->dev);
  		if (ret < 0)
  			goto err;
  	}
  
  	platform_set_drvdata(pdev, leds_data);
  
  	return 0;
  
  err:
  	for (i = i - 1; i >= 0; i--)
  		delete_lt3593_led(&leds_data[i]);
a8dd18feb   Daniel Mack   leds: Add driver ...
144
145
  	return ret;
  }
678e8a6be   Bill Pemberton   leds: remove use ...
146
  static int lt3593_led_remove(struct platform_device *pdev)
a8dd18feb   Daniel Mack   leds: Add driver ...
147
148
  {
  	int i;
87aae1ea8   Jingoo Han   leds: use dev_get...
149
  	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
a8dd18feb   Daniel Mack   leds: Add driver ...
150
151
152
153
154
155
  	struct lt3593_led_data *leds_data;
  
  	leds_data = platform_get_drvdata(pdev);
  
  	for (i = 0; i < pdata->num_leds; i++)
  		delete_lt3593_led(&leds_data[i]);
a8dd18feb   Daniel Mack   leds: Add driver ...
156
157
158
159
160
  	return 0;
  }
  
  static struct platform_driver lt3593_led_driver = {
  	.probe		= lt3593_led_probe,
df07cf812   Bill Pemberton   leds: remove use ...
161
  	.remove		= lt3593_led_remove,
a8dd18feb   Daniel Mack   leds: Add driver ...
162
163
  	.driver		= {
  		.name	= "leds-lt3593",
a8dd18feb   Daniel Mack   leds: Add driver ...
164
165
  	},
  };
892a8843f   Axel Lin   leds: convert led...
166
  module_platform_driver(lt3593_led_driver);
a8dd18feb   Daniel Mack   leds: Add driver ...
167
168
169
170
  
  MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
  MODULE_DESCRIPTION("LED driver for LT3593 controllers");
  MODULE_LICENSE("GPL");
892a8843f   Axel Lin   leds: convert led...
171
  MODULE_ALIAS("platform:leds-lt3593");