2 * Copyright (C) 2010 Motorola, Inc.
4 * This program is free dispware; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free dispware Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free dispware
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 #include <linux/err.h>
20 #include <linux/leds.h>
21 #include <linux/leds-ld-cpcap.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/workqueue.h>
25 #include <linux/regulator/consumer.h>
26 #include <linux/spi/cpcap.h>
27 #include <linux/spi/cpcap-regbits.h>
29 struct cpcap_led_data {
30 struct led_classdev cpcap_class_dev;
31 struct cpcap_device *cpcap;
32 struct cpcap_led *pdata;
33 struct regulator *regulator;
34 struct work_struct brightness_work;
35 enum led_brightness brightness;
39 static void cpcap_set(struct led_classdev *led_cdev,
40 enum led_brightness brightness)
42 struct cpcap_led_data *cpcap_led_data =
43 container_of(led_cdev, struct cpcap_led_data,
49 cpcap_led_data->brightness = brightness;
50 schedule_work(&cpcap_led_data->brightness_work);
52 EXPORT_SYMBOL(cpcap_set);
54 static void cpcap_brightness_work(struct work_struct *work)
57 unsigned short brightness = 0;
59 struct cpcap_led_data *cpcap_led_data =
60 container_of(work, struct cpcap_led_data, brightness_work);
62 brightness = cpcap_led_data->brightness;
65 brightness = (cpcap_led_data->pdata->cpcap_duty_cycle |
66 cpcap_led_data->pdata->cpcap_current | 0x01);
68 if ((cpcap_led_data->regulator) &&
69 (cpcap_led_data->regulator_state == 0)) {
70 regulator_enable(cpcap_led_data->regulator);
71 cpcap_led_data->regulator_state = 1;
74 cpcap_status = cpcap_regacc_write(cpcap_led_data->cpcap,
75 cpcap_led_data->pdata->cpcap_register,
77 cpcap_led_data->pdata->cpcap_mask);
80 pr_err("%s: Writing to the register failed for %i\n",
81 __func__, cpcap_status);
84 if ((cpcap_led_data->regulator) &&
85 (cpcap_led_data->regulator_state == 1)) {
86 regulator_disable(cpcap_led_data->regulator);
87 cpcap_led_data->regulator_state = 0;
89 /* Due to a HW issue turn off the current then
90 turn off the duty cycle */
92 cpcap_status = cpcap_regacc_write(cpcap_led_data->cpcap,
93 cpcap_led_data->pdata->cpcap_register,
95 cpcap_led_data->pdata->cpcap_mask);
99 cpcap_status = cpcap_regacc_write(cpcap_led_data->cpcap,
100 cpcap_led_data->pdata->cpcap_register,
102 cpcap_led_data->pdata->cpcap_mask);
105 if (cpcap_status < 0)
106 pr_err("%s: Writing to the register failed for %i\n",
107 __func__, cpcap_status);
111 static int cpcap_probe(struct platform_device *pdev)
114 struct cpcap_led_data *info;
117 pr_err("%s: platform data required\n", __func__);
121 info = kzalloc(sizeof(struct cpcap_led_data), GFP_KERNEL);
127 info->pdata = pdev->dev.platform_data;
128 info->cpcap = platform_get_drvdata(pdev);
129 platform_set_drvdata(pdev, info);
131 if (info->pdata->led_regulator != NULL) {
132 info->regulator = regulator_get(&pdev->dev,
133 info->pdata->led_regulator);
134 if (IS_ERR(info->regulator)) {
135 pr_err("%s: Cannot get %s regulator\n",
136 __func__, info->pdata->led_regulator);
137 ret = PTR_ERR(info->regulator);
138 goto exit_request_reg_failed;
142 info->regulator_state = 0;
144 info->cpcap_class_dev.name = info->pdata->class_name;
145 info->cpcap_class_dev.brightness_set = cpcap_set;
146 ret = led_classdev_register(&pdev->dev, &info->cpcap_class_dev);
148 pr_err("%s:Register %s class failed\n",
149 __func__, info->cpcap_class_dev.name);
150 goto err_reg_button_class_failed;
152 INIT_WORK(&info->brightness_work, cpcap_brightness_work);
155 err_reg_button_class_failed:
157 regulator_put(info->regulator);
158 exit_request_reg_failed:
163 static int cpcap_remove(struct platform_device *pdev)
165 struct cpcap_led_data *info = platform_get_drvdata(pdev);
168 regulator_put(info->regulator);
170 led_classdev_unregister(&info->cpcap_class_dev);
174 static struct platform_driver ld_cpcap_driver = {
175 .probe = cpcap_probe,
176 .remove = cpcap_remove,
178 .name = LD_CPCAP_LED_DRV,
182 static int __init led_cpcap_init(void)
184 return platform_driver_register(&ld_cpcap_driver);
187 static void __exit led_cpcap_exit(void)
189 platform_driver_unregister(&ld_cpcap_driver);
192 module_init(led_cpcap_init);
193 module_exit(led_cpcap_exit);
195 MODULE_DESCRIPTION("CPCAP Lighting driver");
196 MODULE_AUTHOR("Dan Murphy <D.Murphy@Motorola.com>");
197 MODULE_LICENSE("GPL");