123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- /* include/asm/mach-msm/leds-cpld.c
- *
- * Copyright (C) 2008 HTC Corporation.
- *
- * Author: Farmer Tseng
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/device.h>
- #include <linux/leds.h>
- #include <linux/spinlock.h>
- #include <linux/ctype.h>
- #include <linux/platform_device.h>
- #include <linux/io.h>
- #include <asm/mach-types.h>
- #define DEBUG_LED_CHANGE 0
- static int _g_cpld_led_addr;
- struct CPLD_LED_data {
- spinlock_t data_lock;
- struct led_classdev leds[4]; /* blue, green, red */
- };
- static ssize_t led_blink_solid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct CPLD_LED_data *CPLD_LED;
- int idx = 2;
- uint8_t reg_val;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret = 0;
- if (!strcmp(led_cdev->name, "red"))
- idx = 0;
- else if (!strcmp(led_cdev->name, "green"))
- idx = 1;
- else
- idx = 2;
- CPLD_LED = container_of(led_cdev, struct CPLD_LED_data, leds[idx]);
- spin_lock(&CPLD_LED->data_lock);
- reg_val = readb(_g_cpld_led_addr);
- reg_val = reg_val >> (2 * idx + 1);
- reg_val &= 0x1;
- spin_unlock(&CPLD_LED->data_lock);
- /* no lock needed for this */
- sprintf(buf, "%u\n", reg_val);
- ret = strlen(buf) + 1;
- return ret;
- }
- static ssize_t led_blink_solid_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
- {
- struct CPLD_LED_data *CPLD_LED;
- int idx = 2;
- uint8_t reg_val;
- char *after;
- unsigned long state;
- ssize_t ret = -EINVAL;
- size_t count;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- if (!strcmp(led_cdev->name, "red"))
- idx = 0;
- else if (!strcmp(led_cdev->name, "green"))
- idx = 1;
- else
- idx = 2;
- CPLD_LED = container_of(led_cdev, struct CPLD_LED_data, leds[idx]);
- state = simple_strtoul(buf, &after, 10);
- count = after - buf;
- if (*after && isspace(*after))
- count++;
- if (count == size) {
- ret = count;
- spin_lock(&CPLD_LED->data_lock);
- reg_val = readb(_g_cpld_led_addr);
- if (state)
- reg_val |= 1 << (2 * idx + 1);
- else
- reg_val &= ~(1 << (2 * idx + 1));
- writeb(reg_val, _g_cpld_led_addr);
- spin_unlock(&CPLD_LED->data_lock);
- }
- return ret;
- }
- static DEVICE_ATTR(blink, 0644, led_blink_solid_show, led_blink_solid_store);
- static ssize_t cpldled_blink_all_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- uint8_t reg_val;
- struct CPLD_LED_data *CPLD_LED = dev_get_drvdata(dev);
- ssize_t ret = 0;
- spin_lock(&CPLD_LED->data_lock);
- reg_val = readb(_g_cpld_led_addr);
- reg_val &= 0x2A;
- if (reg_val == 0x2A)
- reg_val = 1;
- else
- reg_val = 0;
- spin_unlock(&CPLD_LED->data_lock);
- /* no lock needed for this */
- sprintf(buf, "%u\n", reg_val);
- ret = strlen(buf) + 1;
- return ret;
- }
- static ssize_t cpldled_blink_all_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
- {
- uint8_t reg_val;
- char *after;
- unsigned long state;
- ssize_t ret = -EINVAL;
- size_t count;
- struct CPLD_LED_data *CPLD_LED = dev_get_drvdata(dev);
- state = simple_strtoul(buf, &after, 10);
- count = after - buf;
- if (*after && isspace(*after))
- count++;
- if (count == size) {
- ret = count;
- spin_lock(&CPLD_LED->data_lock);
- reg_val = readb(_g_cpld_led_addr);
- if (state)
- reg_val |= 0x2A;
- else
- reg_val &= ~0x2A;
- writeb(reg_val, _g_cpld_led_addr);
- spin_unlock(&CPLD_LED->data_lock);
- }
- return ret;
- }
- static struct device_attribute dev_attr_blink_all = {
- .attr = {
- .name = "blink",
- .mode = 0644,
- },
- .show = cpldled_blink_all_show,
- .store = cpldled_blink_all_store,
- };
- static void led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
- {
- struct CPLD_LED_data *CPLD_LED;
- int idx = 2;
- struct led_classdev *led;
- uint8_t reg_val;
- if (!strcmp(led_cdev->name, "jogball-backlight")) {
- if (brightness > 7)
- reg_val = 1;
- else
- reg_val = brightness;
- writeb(0, _g_cpld_led_addr + 0x8);
- writeb(reg_val, _g_cpld_led_addr + 0x8);
- #if DEBUG_LED_CHANGE
- printk(KERN_INFO "LED change: jogball backlight = %d \n",
- reg_val);
- #endif
- return;
- } else if (!strcmp(led_cdev->name, "red")) {
- idx = 0;
- } else if (!strcmp(led_cdev->name, "green")) {
- idx = 1;
- } else {
- idx = 2;
- }
- CPLD_LED = container_of(led_cdev, struct CPLD_LED_data, leds[idx]);
- spin_lock(&CPLD_LED->data_lock);
- reg_val = readb(_g_cpld_led_addr);
- led = &CPLD_LED->leds[idx];
- if (led->brightness > LED_OFF)
- reg_val |= 1 << (2 * idx);
- else
- reg_val &= ~(1 << (2 * idx));
- writeb(reg_val, _g_cpld_led_addr);
- #if DEBUG_LED_CHANGE
- printk(KERN_INFO "LED change: %s = %d \n", led_cdev->name, led->brightness);
- #endif
- spin_unlock(&CPLD_LED->data_lock);
- }
- static ssize_t cpldled_grpfreq_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%u\n", 0);
- }
- static ssize_t cpldled_grpfreq_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- return 0;
- }
- static DEVICE_ATTR(grpfreq, 0644, cpldled_grpfreq_show, cpldled_grpfreq_store);
- static ssize_t cpldled_grppwm_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%u\n", 0);
- }
- static ssize_t cpldled_grppwm_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- return 0;
- }
- static DEVICE_ATTR(grppwm, 0644, cpldled_grppwm_show, cpldled_grppwm_store);
- static int CPLD_LED_probe(struct platform_device *pdev)
- {
- int ret = 0;
- int i, j;
- struct resource *res;
- struct CPLD_LED_data *CPLD_LED;
- CPLD_LED = kzalloc(sizeof(struct CPLD_LED_data), GFP_KERNEL);
- if (CPLD_LED == NULL) {
- printk(KERN_ERR "CPLD_LED_probe: no memory for device\n");
- ret = -ENOMEM;
- goto err_alloc_failed;
- }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOMEM;
- goto err_alloc_failed;
- }
- _g_cpld_led_addr = res->start;
- if (!_g_cpld_led_addr) {
- ret = -ENOMEM;
- goto err_alloc_failed;
- }
- memset(CPLD_LED, 0, sizeof(struct CPLD_LED_data));
- writeb(0x00, _g_cpld_led_addr);
- CPLD_LED->leds[0].name = "red";
- CPLD_LED->leds[0].brightness_set = led_brightness_set;
- CPLD_LED->leds[1].name = "green";
- CPLD_LED->leds[1].brightness_set = led_brightness_set;
- CPLD_LED->leds[2].name = "blue";
- CPLD_LED->leds[2].brightness_set = led_brightness_set;
- CPLD_LED->leds[3].name = "jogball-backlight";
- CPLD_LED->leds[3].brightness_set = led_brightness_set;
- spin_lock_init(&CPLD_LED->data_lock);
- for (i = 0; i < 4; i++) { /* red, green, blue jogball */
- ret = led_classdev_register(&pdev->dev, &CPLD_LED->leds[i]);
- if (ret) {
- printk(KERN_ERR
- "CPLD_LED: led_classdev_register failed\n");
- goto err_led_classdev_register_failed;
- }
- }
- for (i = 0; i < 3; i++) {
- ret =
- device_create_file(CPLD_LED->leds[i].dev, &dev_attr_blink);
- if (ret) {
- printk(KERN_ERR
- "CPLD_LED: device_create_file failed\n");
- goto err_out_attr_blink;
- }
- }
- dev_set_drvdata(&pdev->dev, CPLD_LED);
- ret = device_create_file(&pdev->dev, &dev_attr_blink_all);
- if (ret) {
- printk(KERN_ERR
- "CPLD_LED: create dev_attr_blink_all failed\n");
- goto err_out_attr_blink;
- }
- ret = device_create_file(&pdev->dev, &dev_attr_grppwm);
- if (ret) {
- printk(KERN_ERR
- "CPLD_LED: create dev_attr_grppwm failed\n");
- goto err_out_attr_grppwm;
- }
- ret = device_create_file(&pdev->dev, &dev_attr_grpfreq);
- if (ret) {
- printk(KERN_ERR
- "CPLD_LED: create dev_attr_grpfreq failed\n");
- goto err_out_attr_grpfreq;
- }
- return 0;
- err_out_attr_grpfreq:
- device_remove_file(&pdev->dev, &dev_attr_grppwm);
- err_out_attr_grppwm:
- device_remove_file(&pdev->dev, &dev_attr_blink_all);
- err_out_attr_blink:
- for (j = 0; j < i; j++)
- device_remove_file(CPLD_LED->leds[j].dev, &dev_attr_blink);
- i = 3;
- err_led_classdev_register_failed:
- for (j = 0; j < i; j++)
- led_classdev_unregister(&CPLD_LED->leds[j]);
- err_alloc_failed:
- kfree(CPLD_LED);
- return ret;
- }
- static int __devexit CPLD_LED_remove(struct platform_device *pdev)
- {
- struct CPLD_LED_data *CPLD_LED;
- int i;
- CPLD_LED = platform_get_drvdata(pdev);
- for (i = 0; i < 3; i++) {
- device_remove_file(CPLD_LED->leds[i].dev, &dev_attr_blink);
- led_classdev_unregister(&CPLD_LED->leds[i]);
- }
- device_remove_file(&pdev->dev, &dev_attr_blink_all);
- device_remove_file(&pdev->dev, &dev_attr_grppwm);
- device_remove_file(&pdev->dev, &dev_attr_grpfreq);
- kfree(CPLD_LED);
- return 0;
- }
- static struct platform_driver CPLD_LED_driver = {
- .probe = CPLD_LED_probe,
- .remove = __devexit_p(CPLD_LED_remove),
- .driver = {
- .name = "leds-cpld",
- .owner = THIS_MODULE,
- },
- };
- static int __init CPLD_LED_init(void)
- {
- return platform_driver_register(&CPLD_LED_driver);
- }
- static void __exit CPLD_LED_exit(void)
- {
- platform_driver_unregister(&CPLD_LED_driver);
- }
- MODULE_AUTHOR("Farmer Tseng");
- MODULE_DESCRIPTION("CPLD_LED driver");
- MODULE_LICENSE("GPL");
- module_init(CPLD_LED_init);
- module_exit(CPLD_LED_exit);
|