0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/err.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/leds.h>
0015 #include <linux/mutex.h>
0016 #include <linux/mfd/lp8788.h>
0017 #include <linux/mfd/lp8788-isink.h>
0018
0019 #define MAX_BRIGHTNESS LP8788_ISINK_MAX_PWM
0020 #define DEFAULT_LED_NAME "keyboard-backlight"
0021
0022 struct lp8788_led {
0023 struct lp8788 *lp;
0024 struct mutex lock;
0025 struct led_classdev led_dev;
0026 enum lp8788_isink_number isink_num;
0027 int on;
0028 };
0029
0030 struct lp8788_led_config {
0031 enum lp8788_isink_scale scale;
0032 enum lp8788_isink_number num;
0033 int iout;
0034 };
0035
0036 static struct lp8788_led_config default_led_config = {
0037 .scale = LP8788_ISINK_SCALE_100mA,
0038 .num = LP8788_ISINK_3,
0039 .iout = 0,
0040 };
0041
0042 static int lp8788_led_init_device(struct lp8788_led *led,
0043 struct lp8788_led_platform_data *pdata)
0044 {
0045 struct lp8788_led_config *cfg = &default_led_config;
0046 u8 addr, mask, val;
0047 int ret;
0048
0049 if (pdata) {
0050 cfg->scale = pdata->scale;
0051 cfg->num = pdata->num;
0052 cfg->iout = pdata->iout_code;
0053 }
0054
0055 led->isink_num = cfg->num;
0056
0057
0058 addr = LP8788_ISINK_CTRL;
0059 mask = 1 << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
0060 val = cfg->scale << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
0061 ret = lp8788_update_bits(led->lp, addr, mask, val);
0062 if (ret)
0063 return ret;
0064
0065
0066 addr = lp8788_iout_addr[cfg->num];
0067 mask = lp8788_iout_mask[cfg->num];
0068 val = cfg->iout;
0069
0070 return lp8788_update_bits(led->lp, addr, mask, val);
0071 }
0072
0073 static int lp8788_led_enable(struct lp8788_led *led,
0074 enum lp8788_isink_number num, int on)
0075 {
0076 int ret;
0077
0078 u8 mask = 1 << num;
0079 u8 val = on << num;
0080
0081 ret = lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val);
0082 if (ret == 0)
0083 led->on = on;
0084
0085 return ret;
0086 }
0087
0088 static int lp8788_brightness_set(struct led_classdev *led_cdev,
0089 enum led_brightness val)
0090 {
0091 struct lp8788_led *led =
0092 container_of(led_cdev, struct lp8788_led, led_dev);
0093
0094 enum lp8788_isink_number num = led->isink_num;
0095 int enable, ret;
0096
0097 mutex_lock(&led->lock);
0098
0099 switch (num) {
0100 case LP8788_ISINK_1:
0101 case LP8788_ISINK_2:
0102 case LP8788_ISINK_3:
0103 ret = lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
0104 if (ret < 0)
0105 goto unlock;
0106 break;
0107 default:
0108 mutex_unlock(&led->lock);
0109 return -EINVAL;
0110 }
0111
0112 enable = (val > 0) ? 1 : 0;
0113 if (enable != led->on)
0114 ret = lp8788_led_enable(led, num, enable);
0115 unlock:
0116 mutex_unlock(&led->lock);
0117 return ret;
0118 }
0119
0120 static int lp8788_led_probe(struct platform_device *pdev)
0121 {
0122 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
0123 struct lp8788_led_platform_data *led_pdata;
0124 struct lp8788_led *led;
0125 struct device *dev = &pdev->dev;
0126 int ret;
0127
0128 led = devm_kzalloc(dev, sizeof(struct lp8788_led), GFP_KERNEL);
0129 if (!led)
0130 return -ENOMEM;
0131
0132 led->lp = lp;
0133 led->led_dev.max_brightness = MAX_BRIGHTNESS;
0134 led->led_dev.brightness_set_blocking = lp8788_brightness_set;
0135
0136 led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL;
0137
0138 if (!led_pdata || !led_pdata->name)
0139 led->led_dev.name = DEFAULT_LED_NAME;
0140 else
0141 led->led_dev.name = led_pdata->name;
0142
0143 mutex_init(&led->lock);
0144
0145 ret = lp8788_led_init_device(led, led_pdata);
0146 if (ret) {
0147 dev_err(dev, "led init device err: %d\n", ret);
0148 return ret;
0149 }
0150
0151 ret = devm_led_classdev_register(dev, &led->led_dev);
0152 if (ret) {
0153 dev_err(dev, "led register err: %d\n", ret);
0154 return ret;
0155 }
0156
0157 return 0;
0158 }
0159
0160 static struct platform_driver lp8788_led_driver = {
0161 .probe = lp8788_led_probe,
0162 .driver = {
0163 .name = LP8788_DEV_KEYLED,
0164 },
0165 };
0166 module_platform_driver(lp8788_led_driver);
0167
0168 MODULE_DESCRIPTION("Texas Instruments LP8788 Keyboard LED Driver");
0169 MODULE_AUTHOR("Milo Kim");
0170 MODULE_LICENSE("GPL");
0171 MODULE_ALIAS("platform:lp8788-keyled");