root/drivers/leds/leds-max8997.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. max8997_led_set_mode
  2. max8997_led_enable
  3. max8997_led_set_current
  4. max8997_led_brightness_set
  5. max8997_led_show_mode
  6. max8997_led_store_mode
  7. max8997_led_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * leds-max8997.c - LED class driver for MAX8997 LEDs.
   4  *
   5  * Copyright (C) 2011 Samsung Electronics
   6  * Donggeun Kim <dg77.kim@samsung.com>
   7  */
   8 
   9 #include <linux/module.h>
  10 #include <linux/err.h>
  11 #include <linux/slab.h>
  12 #include <linux/leds.h>
  13 #include <linux/mfd/max8997.h>
  14 #include <linux/mfd/max8997-private.h>
  15 #include <linux/platform_device.h>
  16 
  17 #define MAX8997_LED_FLASH_SHIFT                 3
  18 #define MAX8997_LED_FLASH_CUR_MASK              0xf8
  19 #define MAX8997_LED_MOVIE_SHIFT                 4
  20 #define MAX8997_LED_MOVIE_CUR_MASK              0xf0
  21 
  22 #define MAX8997_LED_FLASH_MAX_BRIGHTNESS        0x1f
  23 #define MAX8997_LED_MOVIE_MAX_BRIGHTNESS        0xf
  24 #define MAX8997_LED_NONE_MAX_BRIGHTNESS         0
  25 
  26 #define MAX8997_LED0_FLASH_MASK                 0x1
  27 #define MAX8997_LED0_FLASH_PIN_MASK             0x5
  28 #define MAX8997_LED0_MOVIE_MASK                 0x8
  29 #define MAX8997_LED0_MOVIE_PIN_MASK             0x28
  30 
  31 #define MAX8997_LED1_FLASH_MASK                 0x2
  32 #define MAX8997_LED1_FLASH_PIN_MASK             0x6
  33 #define MAX8997_LED1_MOVIE_MASK                 0x10
  34 #define MAX8997_LED1_MOVIE_PIN_MASK             0x30
  35 
  36 #define MAX8997_LED_BOOST_ENABLE_MASK           (1 << 6)
  37 
  38 struct max8997_led {
  39         struct max8997_dev *iodev;
  40         struct led_classdev cdev;
  41         bool enabled;
  42         int id;
  43         enum max8997_led_mode led_mode;
  44         struct mutex mutex;
  45 };
  46 
  47 static void max8997_led_set_mode(struct max8997_led *led,
  48                         enum max8997_led_mode mode)
  49 {
  50         int ret;
  51         struct i2c_client *client = led->iodev->i2c;
  52         u8 mask = 0, val;
  53 
  54         switch (mode) {
  55         case MAX8997_FLASH_MODE:
  56                 mask = MAX8997_LED1_FLASH_MASK | MAX8997_LED0_FLASH_MASK;
  57                 val = led->id ?
  58                       MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
  59                 led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
  60                 break;
  61         case MAX8997_MOVIE_MODE:
  62                 mask = MAX8997_LED1_MOVIE_MASK | MAX8997_LED0_MOVIE_MASK;
  63                 val = led->id ?
  64                       MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
  65                 led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
  66                 break;
  67         case MAX8997_FLASH_PIN_CONTROL_MODE:
  68                 mask = MAX8997_LED1_FLASH_PIN_MASK |
  69                        MAX8997_LED0_FLASH_PIN_MASK;
  70                 val = led->id ?
  71                       MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
  72                 led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
  73                 break;
  74         case MAX8997_MOVIE_PIN_CONTROL_MODE:
  75                 mask = MAX8997_LED1_MOVIE_PIN_MASK |
  76                        MAX8997_LED0_MOVIE_PIN_MASK;
  77                 val = led->id ?
  78                       MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
  79                 led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
  80                 break;
  81         default:
  82                 led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS;
  83                 break;
  84         }
  85 
  86         if (mask) {
  87                 ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val,
  88                                          mask);
  89                 if (ret)
  90                         dev_err(led->iodev->dev,
  91                                 "failed to update register(%d)\n", ret);
  92         }
  93 
  94         led->led_mode = mode;
  95 }
  96 
  97 static void max8997_led_enable(struct max8997_led *led, bool enable)
  98 {
  99         int ret;
 100         struct i2c_client *client = led->iodev->i2c;
 101         u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK;
 102 
 103         if (led->enabled == enable)
 104                 return;
 105 
 106         val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0;
 107 
 108         ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask);
 109         if (ret)
 110                 dev_err(led->iodev->dev,
 111                         "failed to update register(%d)\n", ret);
 112 
 113         led->enabled = enable;
 114 }
 115 
 116 static void max8997_led_set_current(struct max8997_led *led,
 117                                 enum led_brightness value)
 118 {
 119         int ret;
 120         struct i2c_client *client = led->iodev->i2c;
 121         u8 val = 0, mask = 0, reg = 0;
 122 
 123         switch (led->led_mode) {
 124         case MAX8997_FLASH_MODE:
 125         case MAX8997_FLASH_PIN_CONTROL_MODE:
 126                 val = value << MAX8997_LED_FLASH_SHIFT;
 127                 mask = MAX8997_LED_FLASH_CUR_MASK;
 128                 reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR;
 129                 break;
 130         case MAX8997_MOVIE_MODE:
 131         case MAX8997_MOVIE_PIN_CONTROL_MODE:
 132                 val = value << MAX8997_LED_MOVIE_SHIFT;
 133                 mask = MAX8997_LED_MOVIE_CUR_MASK;
 134                 reg = MAX8997_REG_MOVIE_CUR;
 135                 break;
 136         default:
 137                 break;
 138         }
 139 
 140         if (mask) {
 141                 ret = max8997_update_reg(client, reg, val, mask);
 142                 if (ret)
 143                         dev_err(led->iodev->dev,
 144                                 "failed to update register(%d)\n", ret);
 145         }
 146 }
 147 
 148 static void max8997_led_brightness_set(struct led_classdev *led_cdev,
 149                                 enum led_brightness value)
 150 {
 151         struct max8997_led *led =
 152                         container_of(led_cdev, struct max8997_led, cdev);
 153 
 154         if (value) {
 155                 max8997_led_set_current(led, value);
 156                 max8997_led_enable(led, true);
 157         } else {
 158                 max8997_led_set_current(led, value);
 159                 max8997_led_enable(led, false);
 160         }
 161 }
 162 
 163 static ssize_t max8997_led_show_mode(struct device *dev,
 164                                 struct device_attribute *attr, char *buf)
 165 {
 166         struct led_classdev *led_cdev = dev_get_drvdata(dev);
 167         struct max8997_led *led =
 168                         container_of(led_cdev, struct max8997_led, cdev);
 169         ssize_t ret = 0;
 170 
 171         mutex_lock(&led->mutex);
 172 
 173         switch (led->led_mode) {
 174         case MAX8997_FLASH_MODE:
 175                 ret += sprintf(buf, "FLASH\n");
 176                 break;
 177         case MAX8997_MOVIE_MODE:
 178                 ret += sprintf(buf, "MOVIE\n");
 179                 break;
 180         case MAX8997_FLASH_PIN_CONTROL_MODE:
 181                 ret += sprintf(buf, "FLASH_PIN_CONTROL\n");
 182                 break;
 183         case MAX8997_MOVIE_PIN_CONTROL_MODE:
 184                 ret += sprintf(buf, "MOVIE_PIN_CONTROL\n");
 185                 break;
 186         default:
 187                 ret += sprintf(buf, "NONE\n");
 188                 break;
 189         }
 190 
 191         mutex_unlock(&led->mutex);
 192 
 193         return ret;
 194 }
 195 
 196 static ssize_t max8997_led_store_mode(struct device *dev,
 197                                 struct device_attribute *attr,
 198                                 const char *buf, size_t size)
 199 {
 200         struct led_classdev *led_cdev = dev_get_drvdata(dev);
 201         struct max8997_led *led =
 202                         container_of(led_cdev, struct max8997_led, cdev);
 203         enum max8997_led_mode mode;
 204 
 205         mutex_lock(&led->mutex);
 206 
 207         if (!strncmp(buf, "FLASH_PIN_CONTROL", 17))
 208                 mode = MAX8997_FLASH_PIN_CONTROL_MODE;
 209         else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17))
 210                 mode = MAX8997_MOVIE_PIN_CONTROL_MODE;
 211         else if (!strncmp(buf, "FLASH", 5))
 212                 mode = MAX8997_FLASH_MODE;
 213         else if (!strncmp(buf, "MOVIE", 5))
 214                 mode = MAX8997_MOVIE_MODE;
 215         else
 216                 mode = MAX8997_NONE;
 217 
 218         max8997_led_set_mode(led, mode);
 219 
 220         mutex_unlock(&led->mutex);
 221 
 222         return size;
 223 }
 224 
 225 static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode);
 226 
 227 static struct attribute *max8997_attrs[] = {
 228         &dev_attr_mode.attr,
 229         NULL
 230 };
 231 ATTRIBUTE_GROUPS(max8997);
 232 
 233 static int max8997_led_probe(struct platform_device *pdev)
 234 {
 235         struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
 236         struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
 237         struct max8997_led *led;
 238         char name[20];
 239         int ret = 0;
 240 
 241         if (pdata == NULL) {
 242                 dev_err(&pdev->dev, "no platform data\n");
 243                 return -ENODEV;
 244         }
 245 
 246         led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
 247         if (led == NULL)
 248                 return -ENOMEM;
 249 
 250         led->id = pdev->id;
 251         snprintf(name, sizeof(name), "max8997-led%d", pdev->id);
 252 
 253         led->cdev.name = name;
 254         led->cdev.brightness_set = max8997_led_brightness_set;
 255         led->cdev.flags |= LED_CORE_SUSPENDRESUME;
 256         led->cdev.brightness = 0;
 257         led->cdev.groups = max8997_groups;
 258         led->iodev = iodev;
 259 
 260         /* initialize mode and brightness according to platform_data */
 261         if (pdata->led_pdata) {
 262                 u8 mode = 0, brightness = 0;
 263 
 264                 mode = pdata->led_pdata->mode[led->id];
 265                 brightness = pdata->led_pdata->brightness[led->id];
 266 
 267                 max8997_led_set_mode(led, mode);
 268 
 269                 if (brightness > led->cdev.max_brightness)
 270                         brightness = led->cdev.max_brightness;
 271                 max8997_led_set_current(led, brightness);
 272                 led->cdev.brightness = brightness;
 273         } else {
 274                 max8997_led_set_mode(led, MAX8997_NONE);
 275                 max8997_led_set_current(led, 0);
 276         }
 277 
 278         mutex_init(&led->mutex);
 279 
 280         ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
 281         if (ret < 0)
 282                 return ret;
 283 
 284         return 0;
 285 }
 286 
 287 static struct platform_driver max8997_led_driver = {
 288         .driver = {
 289                 .name  = "max8997-led",
 290         },
 291         .probe  = max8997_led_probe,
 292 };
 293 
 294 module_platform_driver(max8997_led_driver);
 295 
 296 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
 297 MODULE_DESCRIPTION("MAX8997 LED driver");
 298 MODULE_LICENSE("GPL");
 299 MODULE_ALIAS("platform:max8997-led");

/* [<][>][^][v][top][bottom][index][help] */