0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/leds.h>
0011 #include <linux/err.h>
0012 #include <linux/mfd/wm8350/pmic.h>
0013 #include <linux/regulator/consumer.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016
0017
0018 static const int isink_cur[] = {
0019 4,
0020 5,
0021 6,
0022 7,
0023 8,
0024 10,
0025 11,
0026 14,
0027 16,
0028 19,
0029 23,
0030 27,
0031 32,
0032 39,
0033 46,
0034 54,
0035 65,
0036 77,
0037 92,
0038 109,
0039 130,
0040 154,
0041 183,
0042 218,
0043 259,
0044 308,
0045 367,
0046 436,
0047 518,
0048 616,
0049 733,
0050 872,
0051 1037,
0052 1233,
0053 1466,
0054 1744,
0055 2073,
0056 2466,
0057 2933,
0058 3487,
0059 4147,
0060 4932,
0061 5865,
0062 6975,
0063 8294,
0064 9864,
0065 11730,
0066 13949,
0067 16589,
0068 19728,
0069 23460,
0070 27899,
0071 33178,
0072 39455,
0073 46920,
0074 55798,
0075 66355,
0076 78910,
0077 93840,
0078 111596,
0079 132710,
0080 157820,
0081 187681,
0082 223191
0083 };
0084
0085 #define to_wm8350_led(led_cdev) \
0086 container_of(led_cdev, struct wm8350_led, cdev)
0087
0088 static int wm8350_led_enable(struct wm8350_led *led)
0089 {
0090 int ret = 0;
0091
0092 if (led->enabled)
0093 return ret;
0094
0095 ret = regulator_enable(led->isink);
0096 if (ret != 0) {
0097 dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret);
0098 return ret;
0099 }
0100
0101 ret = regulator_enable(led->dcdc);
0102 if (ret != 0) {
0103 dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret);
0104 regulator_disable(led->isink);
0105 return ret;
0106 }
0107
0108 led->enabled = 1;
0109
0110 return ret;
0111 }
0112
0113 static int wm8350_led_disable(struct wm8350_led *led)
0114 {
0115 int ret = 0;
0116
0117 if (!led->enabled)
0118 return ret;
0119
0120 ret = regulator_disable(led->dcdc);
0121 if (ret != 0) {
0122 dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret);
0123 return ret;
0124 }
0125
0126 ret = regulator_disable(led->isink);
0127 if (ret != 0) {
0128 dev_err(led->cdev.dev, "Failed to disable ISINK: %d\n", ret);
0129 ret = regulator_enable(led->dcdc);
0130 if (ret != 0)
0131 dev_err(led->cdev.dev, "Failed to reenable DCDC: %d\n",
0132 ret);
0133 return ret;
0134 }
0135
0136 led->enabled = 0;
0137
0138 return ret;
0139 }
0140
0141 static int wm8350_led_set(struct led_classdev *led_cdev,
0142 enum led_brightness value)
0143 {
0144 struct wm8350_led *led = to_wm8350_led(led_cdev);
0145 unsigned long flags;
0146 int ret;
0147 int uA;
0148
0149 led->value = value;
0150
0151 spin_lock_irqsave(&led->value_lock, flags);
0152
0153 if (led->value == LED_OFF) {
0154 spin_unlock_irqrestore(&led->value_lock, flags);
0155 return wm8350_led_disable(led);
0156 }
0157
0158
0159
0160
0161
0162
0163 uA = (led->max_uA_index * led->value) / LED_FULL;
0164 spin_unlock_irqrestore(&led->value_lock, flags);
0165 BUG_ON(uA >= ARRAY_SIZE(isink_cur));
0166
0167 ret = regulator_set_current_limit(led->isink, isink_cur[uA],
0168 isink_cur[uA]);
0169 if (ret != 0) {
0170 dev_err(led->cdev.dev, "Failed to set %duA: %d\n",
0171 isink_cur[uA], ret);
0172 return ret;
0173 }
0174
0175 return wm8350_led_enable(led);
0176 }
0177
0178 static void wm8350_led_shutdown(struct platform_device *pdev)
0179 {
0180 struct wm8350_led *led = platform_get_drvdata(pdev);
0181
0182 led->value = LED_OFF;
0183 wm8350_led_disable(led);
0184 }
0185
0186 static int wm8350_led_probe(struct platform_device *pdev)
0187 {
0188 struct regulator *isink, *dcdc;
0189 struct wm8350_led *led;
0190 struct wm8350_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
0191 int i;
0192
0193 if (pdata == NULL) {
0194 dev_err(&pdev->dev, "no platform data\n");
0195 return -ENODEV;
0196 }
0197
0198 if (pdata->max_uA < isink_cur[0]) {
0199 dev_err(&pdev->dev, "Invalid maximum current %duA\n",
0200 pdata->max_uA);
0201 return -EINVAL;
0202 }
0203
0204 isink = devm_regulator_get(&pdev->dev, "led_isink");
0205 if (IS_ERR(isink)) {
0206 dev_err(&pdev->dev, "%s: can't get ISINK\n", __func__);
0207 return PTR_ERR(isink);
0208 }
0209
0210 dcdc = devm_regulator_get(&pdev->dev, "led_vcc");
0211 if (IS_ERR(dcdc)) {
0212 dev_err(&pdev->dev, "%s: can't get DCDC\n", __func__);
0213 return PTR_ERR(dcdc);
0214 }
0215
0216 led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
0217 if (led == NULL)
0218 return -ENOMEM;
0219
0220 led->cdev.brightness_set_blocking = wm8350_led_set;
0221 led->cdev.default_trigger = pdata->default_trigger;
0222 led->cdev.name = pdata->name;
0223 led->cdev.flags |= LED_CORE_SUSPENDRESUME;
0224 led->enabled = regulator_is_enabled(isink);
0225 led->isink = isink;
0226 led->dcdc = dcdc;
0227
0228 for (i = 0; i < ARRAY_SIZE(isink_cur) - 1; i++)
0229 if (isink_cur[i] >= pdata->max_uA)
0230 break;
0231 led->max_uA_index = i;
0232 if (pdata->max_uA != isink_cur[i])
0233 dev_warn(&pdev->dev,
0234 "Maximum current %duA is not directly supported,"
0235 " check platform data\n",
0236 pdata->max_uA);
0237
0238 spin_lock_init(&led->value_lock);
0239 led->value = LED_OFF;
0240 platform_set_drvdata(pdev, led);
0241
0242 return led_classdev_register(&pdev->dev, &led->cdev);
0243 }
0244
0245 static int wm8350_led_remove(struct platform_device *pdev)
0246 {
0247 struct wm8350_led *led = platform_get_drvdata(pdev);
0248
0249 led_classdev_unregister(&led->cdev);
0250 wm8350_led_disable(led);
0251 return 0;
0252 }
0253
0254 static struct platform_driver wm8350_led_driver = {
0255 .driver = {
0256 .name = "wm8350-led",
0257 },
0258 .probe = wm8350_led_probe,
0259 .remove = wm8350_led_remove,
0260 .shutdown = wm8350_led_shutdown,
0261 };
0262
0263 module_platform_driver(wm8350_led_driver);
0264
0265 MODULE_AUTHOR("Mark Brown");
0266 MODULE_DESCRIPTION("WM8350 LED driver");
0267 MODULE_LICENSE("GPL");
0268 MODULE_ALIAS("platform:wm8350-led");