0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/leds.h>
0019 #include <linux/mfd/adp5520.h>
0020 #include <linux/slab.h>
0021
0022 struct adp5520_led {
0023 struct led_classdev cdev;
0024 struct device *master;
0025 int id;
0026 int flags;
0027 };
0028
0029 static int adp5520_led_set(struct led_classdev *led_cdev,
0030 enum led_brightness value)
0031 {
0032 struct adp5520_led *led;
0033
0034 led = container_of(led_cdev, struct adp5520_led, cdev);
0035 return adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
0036 value >> 2);
0037 }
0038
0039 static int adp5520_led_setup(struct adp5520_led *led)
0040 {
0041 struct device *dev = led->master;
0042 int flags = led->flags;
0043 int ret = 0;
0044
0045 switch (led->id) {
0046 case FLAG_ID_ADP5520_LED1_ADP5501_LED0:
0047 ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
0048 (flags >> ADP5520_FLAG_OFFT_SHIFT) &
0049 ADP5520_FLAG_OFFT_MASK);
0050 ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
0051 ADP5520_LED1_EN);
0052 break;
0053 case FLAG_ID_ADP5520_LED2_ADP5501_LED1:
0054 ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
0055 ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
0056 ADP5520_FLAG_OFFT_MASK) << 2);
0057 ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
0058 ADP5520_R3_MODE);
0059 ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
0060 ADP5520_LED2_EN);
0061 break;
0062 case FLAG_ID_ADP5520_LED3_ADP5501_LED2:
0063 ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
0064 ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
0065 ADP5520_FLAG_OFFT_MASK) << 4);
0066 ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
0067 ADP5520_C3_MODE);
0068 ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
0069 ADP5520_LED3_EN);
0070 break;
0071 }
0072
0073 return ret;
0074 }
0075
0076 static int adp5520_led_prepare(struct platform_device *pdev)
0077 {
0078 struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
0079 struct device *dev = pdev->dev.parent;
0080 int ret = 0;
0081
0082 ret |= adp5520_write(dev, ADP5520_LED1_CURRENT, 0);
0083 ret |= adp5520_write(dev, ADP5520_LED2_CURRENT, 0);
0084 ret |= adp5520_write(dev, ADP5520_LED3_CURRENT, 0);
0085 ret |= adp5520_write(dev, ADP5520_LED_TIME, pdata->led_on_time << 6);
0086 ret |= adp5520_write(dev, ADP5520_LED_FADE, FADE_VAL(pdata->fade_in,
0087 pdata->fade_out));
0088
0089 return ret;
0090 }
0091
0092 static int adp5520_led_probe(struct platform_device *pdev)
0093 {
0094 struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
0095 struct adp5520_led *led, *led_dat;
0096 struct led_info *cur_led;
0097 int ret, i;
0098
0099 if (pdata == NULL) {
0100 dev_err(&pdev->dev, "missing platform data\n");
0101 return -ENODEV;
0102 }
0103
0104 if (pdata->num_leds > ADP5520_01_MAXLEDS) {
0105 dev_err(&pdev->dev, "can't handle more than %d LEDS\n",
0106 ADP5520_01_MAXLEDS);
0107 return -EFAULT;
0108 }
0109
0110 led = devm_kcalloc(&pdev->dev, pdata->num_leds, sizeof(*led),
0111 GFP_KERNEL);
0112 if (!led)
0113 return -ENOMEM;
0114
0115 ret = adp5520_led_prepare(pdev);
0116 if (ret) {
0117 dev_err(&pdev->dev, "failed to write\n");
0118 return ret;
0119 }
0120
0121 for (i = 0; i < pdata->num_leds; ++i) {
0122 cur_led = &pdata->leds[i];
0123 led_dat = &led[i];
0124
0125 led_dat->cdev.name = cur_led->name;
0126 led_dat->cdev.default_trigger = cur_led->default_trigger;
0127 led_dat->cdev.brightness_set_blocking = adp5520_led_set;
0128 led_dat->cdev.brightness = LED_OFF;
0129
0130 if (cur_led->flags & ADP5520_FLAG_LED_MASK)
0131 led_dat->flags = cur_led->flags;
0132 else
0133 led_dat->flags = i + 1;
0134
0135 led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
0136
0137 led_dat->master = pdev->dev.parent;
0138
0139 ret = led_classdev_register(led_dat->master, &led_dat->cdev);
0140 if (ret) {
0141 dev_err(&pdev->dev, "failed to register LED %d\n",
0142 led_dat->id);
0143 goto err;
0144 }
0145
0146 ret = adp5520_led_setup(led_dat);
0147 if (ret) {
0148 dev_err(&pdev->dev, "failed to write\n");
0149 i++;
0150 goto err;
0151 }
0152 }
0153
0154 platform_set_drvdata(pdev, led);
0155 return 0;
0156
0157 err:
0158 if (i > 0) {
0159 for (i = i - 1; i >= 0; i--)
0160 led_classdev_unregister(&led[i].cdev);
0161 }
0162
0163 return ret;
0164 }
0165
0166 static int adp5520_led_remove(struct platform_device *pdev)
0167 {
0168 struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
0169 struct adp5520_led *led;
0170 int i;
0171
0172 led = platform_get_drvdata(pdev);
0173
0174 adp5520_clr_bits(led->master, ADP5520_LED_CONTROL,
0175 ADP5520_LED1_EN | ADP5520_LED2_EN | ADP5520_LED3_EN);
0176
0177 for (i = 0; i < pdata->num_leds; i++) {
0178 led_classdev_unregister(&led[i].cdev);
0179 }
0180
0181 return 0;
0182 }
0183
0184 static struct platform_driver adp5520_led_driver = {
0185 .driver = {
0186 .name = "adp5520-led",
0187 },
0188 .probe = adp5520_led_probe,
0189 .remove = adp5520_led_remove,
0190 };
0191
0192 module_platform_driver(adp5520_led_driver);
0193
0194 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
0195 MODULE_DESCRIPTION("LEDS ADP5520(01) Driver");
0196 MODULE_LICENSE("GPL");
0197 MODULE_ALIAS("platform:adp5520-led");