forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an LED driver using the DAC124S085 DAC from NatSemi [[email protected]: use header files for interfaces] Signed-off-by: Guennadi Liakhovetski <[email protected]> Signed-off-by: Randy Dunlap <[email protected]> Signed-off-by: Richard Purdie <[email protected]>
- Loading branch information
Showing
3 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* | ||
* Copyright 2008 | ||
* Guennadi Liakhovetski, DENX Software Engineering, <[email protected]> | ||
* | ||
* This file is subject to the terms and conditions of version 2 of | ||
* the GNU General Public License. See the file COPYING in the main | ||
* directory of this archive for more details. | ||
* | ||
* LED driver for the DAC124S085 SPI DAC | ||
*/ | ||
|
||
#include <linux/gfp.h> | ||
#include <linux/leds.h> | ||
#include <linux/module.h> | ||
#include <linux/mutex.h> | ||
#include <linux/slab.h> | ||
#include <linux/spinlock.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/spi/spi.h> | ||
|
||
struct dac124s085_led { | ||
struct led_classdev ldev; | ||
struct spi_device *spi; | ||
int id; | ||
int brightness; | ||
char name[sizeof("dac124s085-3")]; | ||
|
||
struct mutex mutex; | ||
struct work_struct work; | ||
spinlock_t lock; | ||
}; | ||
|
||
struct dac124s085 { | ||
struct dac124s085_led leds[4]; | ||
}; | ||
|
||
#define REG_WRITE (0 << 12) | ||
#define REG_WRITE_UPDATE (1 << 12) | ||
#define ALL_WRITE_UPDATE (2 << 12) | ||
#define POWER_DOWN_OUTPUT (3 << 12) | ||
|
||
static void dac124s085_led_work(struct work_struct *work) | ||
{ | ||
struct dac124s085_led *led = container_of(work, struct dac124s085_led, | ||
work); | ||
u16 word; | ||
|
||
mutex_lock(&led->mutex); | ||
word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE | | ||
(led->brightness & 0xfff)); | ||
spi_write(led->spi, (const u8 *)&word, sizeof(word)); | ||
mutex_unlock(&led->mutex); | ||
} | ||
|
||
static void dac124s085_set_brightness(struct led_classdev *ldev, | ||
enum led_brightness brightness) | ||
{ | ||
struct dac124s085_led *led = container_of(ldev, struct dac124s085_led, | ||
ldev); | ||
|
||
spin_lock(&led->lock); | ||
led->brightness = brightness; | ||
schedule_work(&led->work); | ||
spin_unlock(&led->lock); | ||
} | ||
|
||
static int dac124s085_probe(struct spi_device *spi) | ||
{ | ||
struct dac124s085 *dac; | ||
struct dac124s085_led *led; | ||
int i, ret; | ||
|
||
dac = kzalloc(sizeof(*dac), GFP_KERNEL); | ||
if (!dac) | ||
return -ENOMEM; | ||
|
||
spi->bits_per_word = 16; | ||
|
||
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) { | ||
led = dac->leds + i; | ||
led->id = i; | ||
led->brightness = LED_OFF; | ||
led->spi = spi; | ||
snprintf(led->name, sizeof(led->name), "dac124s085-%d", i); | ||
spin_lock_init(&led->lock); | ||
INIT_WORK(&led->work, dac124s085_led_work); | ||
mutex_init(&led->mutex); | ||
led->ldev.name = led->name; | ||
led->ldev.brightness = LED_OFF; | ||
led->ldev.max_brightness = 0xfff; | ||
led->ldev.brightness_set = dac124s085_set_brightness; | ||
ret = led_classdev_register(&spi->dev, &led->ldev); | ||
if (ret < 0) | ||
goto eledcr; | ||
} | ||
|
||
spi_set_drvdata(spi, dac); | ||
|
||
return 0; | ||
|
||
eledcr: | ||
while (i--) | ||
led_classdev_unregister(&dac->leds[i].ldev); | ||
|
||
spi_set_drvdata(spi, NULL); | ||
kfree(dac); | ||
return ret; | ||
} | ||
|
||
static int dac124s085_remove(struct spi_device *spi) | ||
{ | ||
struct dac124s085 *dac = spi_get_drvdata(spi); | ||
int i; | ||
|
||
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) { | ||
led_classdev_unregister(&dac->leds[i].ldev); | ||
cancel_work_sync(&dac->leds[i].work); | ||
} | ||
|
||
spi_set_drvdata(spi, NULL); | ||
kfree(dac); | ||
|
||
return 0; | ||
} | ||
|
||
static struct spi_driver dac124s085_driver = { | ||
.probe = dac124s085_probe, | ||
.remove = dac124s085_remove, | ||
.driver = { | ||
.name = "dac124s085", | ||
.owner = THIS_MODULE, | ||
}, | ||
}; | ||
|
||
static int __init dac124s085_leds_init(void) | ||
{ | ||
return spi_register_driver(&dac124s085_driver); | ||
} | ||
|
||
static void __exit dac124s085_leds_exit(void) | ||
{ | ||
spi_unregister_driver(&dac124s085_driver); | ||
} | ||
|
||
module_init(dac124s085_leds_init); | ||
module_exit(dac124s085_leds_exit); | ||
|
||
MODULE_AUTHOR("Guennadi Liakhovetski <[email protected]>"); | ||
MODULE_DESCRIPTION("DAC124S085 LED driver"); | ||
MODULE_LICENSE("GPL v2"); |