0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/leds.h>
0016 #include <linux/mfd/da903x.h>
0017 #include <linux/slab.h>
0018
0019 #define DA9030_LED1_CONTROL 0x20
0020 #define DA9030_LED2_CONTROL 0x21
0021 #define DA9030_LED3_CONTROL 0x22
0022 #define DA9030_LED4_CONTROL 0x23
0023 #define DA9030_LEDPC_CONTROL 0x24
0024 #define DA9030_MISC_CONTROL_A 0x26
0025
0026 #define DA9034_LED1_CONTROL 0x35
0027 #define DA9034_LED2_CONTROL 0x36
0028 #define DA9034_VIBRA 0x40
0029
0030 struct da903x_led {
0031 struct led_classdev cdev;
0032 struct device *master;
0033 int id;
0034 int flags;
0035 };
0036
0037 #define DA9030_LED_OFFSET(id) ((id) - DA9030_ID_LED_1)
0038 #define DA9034_LED_OFFSET(id) ((id) - DA9034_ID_LED_1)
0039
0040 static int da903x_led_set(struct led_classdev *led_cdev,
0041 enum led_brightness value)
0042 {
0043 struct da903x_led *led =
0044 container_of(led_cdev, struct da903x_led, cdev);
0045 uint8_t val;
0046 int offset, ret = -EINVAL;
0047
0048 switch (led->id) {
0049 case DA9030_ID_LED_1:
0050 case DA9030_ID_LED_2:
0051 case DA9030_ID_LED_3:
0052 case DA9030_ID_LED_4:
0053 case DA9030_ID_LED_PC:
0054 offset = DA9030_LED_OFFSET(led->id);
0055 val = led->flags & ~0x87;
0056 val |= value ? 0x80 : 0;
0057 val |= (0x7 - (value >> 5)) & 0x7;
0058 ret = da903x_write(led->master, DA9030_LED1_CONTROL + offset,
0059 val);
0060 break;
0061 case DA9030_ID_VIBRA:
0062 val = led->flags & ~0x80;
0063 val |= value ? 0x80 : 0;
0064 ret = da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
0065 break;
0066 case DA9034_ID_LED_1:
0067 case DA9034_ID_LED_2:
0068 offset = DA9034_LED_OFFSET(led->id);
0069 val = (value * 0x5f / LED_FULL) & 0x7f;
0070 val |= (led->flags & DA9034_LED_RAMP) ? 0x80 : 0;
0071 ret = da903x_write(led->master, DA9034_LED1_CONTROL + offset,
0072 val);
0073 break;
0074 case DA9034_ID_VIBRA:
0075 val = value & 0xfe;
0076 ret = da903x_write(led->master, DA9034_VIBRA, val);
0077 break;
0078 }
0079
0080 return ret;
0081 }
0082
0083 static int da903x_led_probe(struct platform_device *pdev)
0084 {
0085 struct led_info *pdata = dev_get_platdata(&pdev->dev);
0086 struct da903x_led *led;
0087 int id, ret;
0088
0089 if (pdata == NULL)
0090 return 0;
0091
0092 id = pdev->id;
0093
0094 if (!((id >= DA9030_ID_LED_1 && id <= DA9030_ID_VIBRA) ||
0095 (id >= DA9034_ID_LED_1 && id <= DA9034_ID_VIBRA))) {
0096 dev_err(&pdev->dev, "invalid LED ID (%d) specified\n", id);
0097 return -EINVAL;
0098 }
0099
0100 led = devm_kzalloc(&pdev->dev, sizeof(struct da903x_led), GFP_KERNEL);
0101 if (!led)
0102 return -ENOMEM;
0103
0104 led->cdev.name = pdata->name;
0105 led->cdev.default_trigger = pdata->default_trigger;
0106 led->cdev.brightness_set_blocking = da903x_led_set;
0107 led->cdev.brightness = LED_OFF;
0108
0109 led->id = id;
0110 led->flags = pdata->flags;
0111 led->master = pdev->dev.parent;
0112
0113 ret = led_classdev_register(led->master, &led->cdev);
0114 if (ret) {
0115 dev_err(&pdev->dev, "failed to register LED %d\n", id);
0116 return ret;
0117 }
0118
0119 platform_set_drvdata(pdev, led);
0120
0121 return 0;
0122 }
0123
0124 static int da903x_led_remove(struct platform_device *pdev)
0125 {
0126 struct da903x_led *led = platform_get_drvdata(pdev);
0127
0128 led_classdev_unregister(&led->cdev);
0129
0130 return 0;
0131 }
0132
0133 static struct platform_driver da903x_led_driver = {
0134 .driver = {
0135 .name = "da903x-led",
0136 },
0137 .probe = da903x_led_probe,
0138 .remove = da903x_led_remove,
0139 };
0140
0141 module_platform_driver(da903x_led_driver);
0142
0143 MODULE_DESCRIPTION("LEDs driver for Dialog Semiconductor DA9030/DA9034");
0144 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
0145 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
0146 MODULE_LICENSE("GPL");
0147 MODULE_ALIAS("platform:da903x-led");