Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * leds-max8997.c - LED class driver for MAX8997 LEDs.
0004  *
0005  * Copyright (C) 2011 Samsung Electronics
0006  * Donggeun Kim <dg77.kim@samsung.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/err.h>
0011 #include <linux/slab.h>
0012 #include <linux/leds.h>
0013 #include <linux/mfd/max8997.h>
0014 #include <linux/mfd/max8997-private.h>
0015 #include <linux/platform_device.h>
0016 
0017 #define MAX8997_LED_FLASH_SHIFT         3
0018 #define MAX8997_LED_FLASH_CUR_MASK      0xf8
0019 #define MAX8997_LED_MOVIE_SHIFT         4
0020 #define MAX8997_LED_MOVIE_CUR_MASK      0xf0
0021 
0022 #define MAX8997_LED_FLASH_MAX_BRIGHTNESS    0x1f
0023 #define MAX8997_LED_MOVIE_MAX_BRIGHTNESS    0xf
0024 #define MAX8997_LED_NONE_MAX_BRIGHTNESS     0
0025 
0026 #define MAX8997_LED0_FLASH_MASK         0x1
0027 #define MAX8997_LED0_FLASH_PIN_MASK     0x5
0028 #define MAX8997_LED0_MOVIE_MASK         0x8
0029 #define MAX8997_LED0_MOVIE_PIN_MASK     0x28
0030 
0031 #define MAX8997_LED1_FLASH_MASK         0x2
0032 #define MAX8997_LED1_FLASH_PIN_MASK     0x6
0033 #define MAX8997_LED1_MOVIE_MASK         0x10
0034 #define MAX8997_LED1_MOVIE_PIN_MASK     0x30
0035 
0036 #define MAX8997_LED_BOOST_ENABLE_MASK       (1 << 6)
0037 
0038 struct max8997_led {
0039     struct max8997_dev *iodev;
0040     struct led_classdev cdev;
0041     bool enabled;
0042     int id;
0043     enum max8997_led_mode led_mode;
0044     struct mutex mutex;
0045 };
0046 
0047 static void max8997_led_set_mode(struct max8997_led *led,
0048             enum max8997_led_mode mode)
0049 {
0050     int ret;
0051     struct i2c_client *client = led->iodev->i2c;
0052     u8 mask = 0, val;
0053 
0054     switch (mode) {
0055     case MAX8997_FLASH_MODE:
0056         mask = MAX8997_LED1_FLASH_MASK | MAX8997_LED0_FLASH_MASK;
0057         val = led->id ?
0058               MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
0059         led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
0060         break;
0061     case MAX8997_MOVIE_MODE:
0062         mask = MAX8997_LED1_MOVIE_MASK | MAX8997_LED0_MOVIE_MASK;
0063         val = led->id ?
0064               MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
0065         led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
0066         break;
0067     case MAX8997_FLASH_PIN_CONTROL_MODE:
0068         mask = MAX8997_LED1_FLASH_PIN_MASK |
0069                MAX8997_LED0_FLASH_PIN_MASK;
0070         val = led->id ?
0071               MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
0072         led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
0073         break;
0074     case MAX8997_MOVIE_PIN_CONTROL_MODE:
0075         mask = MAX8997_LED1_MOVIE_PIN_MASK |
0076                MAX8997_LED0_MOVIE_PIN_MASK;
0077         val = led->id ?
0078               MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
0079         led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
0080         break;
0081     default:
0082         led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS;
0083         break;
0084     }
0085 
0086     if (mask) {
0087         ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val,
0088                      mask);
0089         if (ret)
0090             dev_err(led->iodev->dev,
0091                 "failed to update register(%d)\n", ret);
0092     }
0093 
0094     led->led_mode = mode;
0095 }
0096 
0097 static void max8997_led_enable(struct max8997_led *led, bool enable)
0098 {
0099     int ret;
0100     struct i2c_client *client = led->iodev->i2c;
0101     u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK;
0102 
0103     if (led->enabled == enable)
0104         return;
0105 
0106     val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0;
0107 
0108     ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask);
0109     if (ret)
0110         dev_err(led->iodev->dev,
0111             "failed to update register(%d)\n", ret);
0112 
0113     led->enabled = enable;
0114 }
0115 
0116 static void max8997_led_set_current(struct max8997_led *led,
0117                 enum led_brightness value)
0118 {
0119     int ret;
0120     struct i2c_client *client = led->iodev->i2c;
0121     u8 val = 0, mask = 0, reg = 0;
0122 
0123     switch (led->led_mode) {
0124     case MAX8997_FLASH_MODE:
0125     case MAX8997_FLASH_PIN_CONTROL_MODE:
0126         val = value << MAX8997_LED_FLASH_SHIFT;
0127         mask = MAX8997_LED_FLASH_CUR_MASK;
0128         reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR;
0129         break;
0130     case MAX8997_MOVIE_MODE:
0131     case MAX8997_MOVIE_PIN_CONTROL_MODE:
0132         val = value << MAX8997_LED_MOVIE_SHIFT;
0133         mask = MAX8997_LED_MOVIE_CUR_MASK;
0134         reg = MAX8997_REG_MOVIE_CUR;
0135         break;
0136     default:
0137         break;
0138     }
0139 
0140     if (mask) {
0141         ret = max8997_update_reg(client, reg, val, mask);
0142         if (ret)
0143             dev_err(led->iodev->dev,
0144                 "failed to update register(%d)\n", ret);
0145     }
0146 }
0147 
0148 static void max8997_led_brightness_set(struct led_classdev *led_cdev,
0149                 enum led_brightness value)
0150 {
0151     struct max8997_led *led =
0152             container_of(led_cdev, struct max8997_led, cdev);
0153 
0154     if (value) {
0155         max8997_led_set_current(led, value);
0156         max8997_led_enable(led, true);
0157     } else {
0158         max8997_led_set_current(led, value);
0159         max8997_led_enable(led, false);
0160     }
0161 }
0162 
0163 static ssize_t mode_show(struct device *dev,
0164              struct device_attribute *attr, char *buf)
0165 {
0166     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0167     struct max8997_led *led =
0168             container_of(led_cdev, struct max8997_led, cdev);
0169     ssize_t ret = 0;
0170 
0171     mutex_lock(&led->mutex);
0172 
0173     switch (led->led_mode) {
0174     case MAX8997_FLASH_MODE:
0175         ret += sprintf(buf, "FLASH\n");
0176         break;
0177     case MAX8997_MOVIE_MODE:
0178         ret += sprintf(buf, "MOVIE\n");
0179         break;
0180     case MAX8997_FLASH_PIN_CONTROL_MODE:
0181         ret += sprintf(buf, "FLASH_PIN_CONTROL\n");
0182         break;
0183     case MAX8997_MOVIE_PIN_CONTROL_MODE:
0184         ret += sprintf(buf, "MOVIE_PIN_CONTROL\n");
0185         break;
0186     default:
0187         ret += sprintf(buf, "NONE\n");
0188         break;
0189     }
0190 
0191     mutex_unlock(&led->mutex);
0192 
0193     return ret;
0194 }
0195 
0196 static ssize_t mode_store(struct device *dev,
0197               struct device_attribute *attr,
0198               const char *buf, size_t size)
0199 {
0200     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0201     struct max8997_led *led =
0202             container_of(led_cdev, struct max8997_led, cdev);
0203     enum max8997_led_mode mode;
0204 
0205     mutex_lock(&led->mutex);
0206 
0207     if (!strncmp(buf, "FLASH_PIN_CONTROL", 17))
0208         mode = MAX8997_FLASH_PIN_CONTROL_MODE;
0209     else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17))
0210         mode = MAX8997_MOVIE_PIN_CONTROL_MODE;
0211     else if (!strncmp(buf, "FLASH", 5))
0212         mode = MAX8997_FLASH_MODE;
0213     else if (!strncmp(buf, "MOVIE", 5))
0214         mode = MAX8997_MOVIE_MODE;
0215     else
0216         mode = MAX8997_NONE;
0217 
0218     max8997_led_set_mode(led, mode);
0219 
0220     mutex_unlock(&led->mutex);
0221 
0222     return size;
0223 }
0224 
0225 static DEVICE_ATTR_RW(mode);
0226 
0227 static struct attribute *max8997_attrs[] = {
0228     &dev_attr_mode.attr,
0229     NULL
0230 };
0231 ATTRIBUTE_GROUPS(max8997);
0232 
0233 static int max8997_led_probe(struct platform_device *pdev)
0234 {
0235     struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
0236     struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
0237     struct max8997_led *led;
0238     char name[20];
0239     int ret = 0;
0240 
0241     if (pdata == NULL) {
0242         dev_err(&pdev->dev, "no platform data\n");
0243         return -ENODEV;
0244     }
0245 
0246     led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
0247     if (led == NULL)
0248         return -ENOMEM;
0249 
0250     led->id = pdev->id;
0251     snprintf(name, sizeof(name), "max8997-led%d", pdev->id);
0252 
0253     led->cdev.name = name;
0254     led->cdev.brightness_set = max8997_led_brightness_set;
0255     led->cdev.flags |= LED_CORE_SUSPENDRESUME;
0256     led->cdev.brightness = 0;
0257     led->cdev.groups = max8997_groups;
0258     led->iodev = iodev;
0259 
0260     /* initialize mode and brightness according to platform_data */
0261     if (pdata->led_pdata) {
0262         u8 mode = 0, brightness = 0;
0263 
0264         mode = pdata->led_pdata->mode[led->id];
0265         brightness = pdata->led_pdata->brightness[led->id];
0266 
0267         max8997_led_set_mode(led, mode);
0268 
0269         if (brightness > led->cdev.max_brightness)
0270             brightness = led->cdev.max_brightness;
0271         max8997_led_set_current(led, brightness);
0272         led->cdev.brightness = brightness;
0273     } else {
0274         max8997_led_set_mode(led, MAX8997_NONE);
0275         max8997_led_set_current(led, 0);
0276     }
0277 
0278     mutex_init(&led->mutex);
0279 
0280     ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
0281     if (ret < 0)
0282         return ret;
0283 
0284     return 0;
0285 }
0286 
0287 static struct platform_driver max8997_led_driver = {
0288     .driver = {
0289         .name  = "max8997-led",
0290     },
0291     .probe  = max8997_led_probe,
0292 };
0293 
0294 module_platform_driver(max8997_led_driver);
0295 
0296 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
0297 MODULE_DESCRIPTION("MAX8997 LED driver");
0298 MODULE_LICENSE("GPL");
0299 MODULE_ALIAS("platform:max8997-led");