root/drivers/leds/leds-adp5520.c

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

DEFINITIONS

This source file includes following definitions.
  1. adp5520_led_set
  2. adp5520_led_setup
  3. adp5520_led_prepare
  4. adp5520_led_probe
  5. adp5520_led_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * LEDs driver for Analog Devices ADP5520/ADP5501 MFD PMICs
   4  *
   5  * Copyright 2009 Analog Devices Inc.
   6  *
   7  * Loosely derived from leds-da903x:
   8  * Copyright (C) 2008 Compulab, Ltd.
   9  *      Mike Rapoport <mike@compulab.co.il>
  10  *
  11  * Copyright (C) 2006-2008 Marvell International Ltd.
  12  *      Eric Miao <eric.miao@marvell.com>
  13  */
  14 
  15 #include <linux/module.h>
  16 #include <linux/kernel.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/leds.h>
  19 #include <linux/mfd/adp5520.h>
  20 #include <linux/slab.h>
  21 
  22 struct adp5520_led {
  23         struct led_classdev     cdev;
  24         struct device           *master;
  25         int                     id;
  26         int                     flags;
  27 };
  28 
  29 static int adp5520_led_set(struct led_classdev *led_cdev,
  30                            enum led_brightness value)
  31 {
  32         struct adp5520_led *led;
  33 
  34         led = container_of(led_cdev, struct adp5520_led, cdev);
  35         return adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
  36                          value >> 2);
  37 }
  38 
  39 static int adp5520_led_setup(struct adp5520_led *led)
  40 {
  41         struct device *dev = led->master;
  42         int flags = led->flags;
  43         int ret = 0;
  44 
  45         switch (led->id) {
  46         case FLAG_ID_ADP5520_LED1_ADP5501_LED0:
  47                 ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
  48                                         (flags >> ADP5520_FLAG_OFFT_SHIFT) &
  49                                         ADP5520_FLAG_OFFT_MASK);
  50                 ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
  51                                         ADP5520_LED1_EN);
  52                 break;
  53         case FLAG_ID_ADP5520_LED2_ADP5501_LED1:
  54                 ret |= adp5520_set_bits(dev,  ADP5520_LED_TIME,
  55                                         ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
  56                                         ADP5520_FLAG_OFFT_MASK) << 2);
  57                 ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
  58                                          ADP5520_R3_MODE);
  59                 ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
  60                                         ADP5520_LED2_EN);
  61                 break;
  62         case FLAG_ID_ADP5520_LED3_ADP5501_LED2:
  63                 ret |= adp5520_set_bits(dev,  ADP5520_LED_TIME,
  64                                         ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
  65                                         ADP5520_FLAG_OFFT_MASK) << 4);
  66                 ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
  67                                         ADP5520_C3_MODE);
  68                 ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
  69                                         ADP5520_LED3_EN);
  70                 break;
  71         }
  72 
  73         return ret;
  74 }
  75 
  76 static int adp5520_led_prepare(struct platform_device *pdev)
  77 {
  78         struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
  79         struct device *dev = pdev->dev.parent;
  80         int ret = 0;
  81 
  82         ret |= adp5520_write(dev, ADP5520_LED1_CURRENT, 0);
  83         ret |= adp5520_write(dev, ADP5520_LED2_CURRENT, 0);
  84         ret |= adp5520_write(dev, ADP5520_LED3_CURRENT, 0);
  85         ret |= adp5520_write(dev, ADP5520_LED_TIME, pdata->led_on_time << 6);
  86         ret |= adp5520_write(dev, ADP5520_LED_FADE, FADE_VAL(pdata->fade_in,
  87                  pdata->fade_out));
  88 
  89         return ret;
  90 }
  91 
  92 static int adp5520_led_probe(struct platform_device *pdev)
  93 {
  94         struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
  95         struct adp5520_led *led, *led_dat;
  96         struct led_info *cur_led;
  97         int ret, i;
  98 
  99         if (pdata == NULL) {
 100                 dev_err(&pdev->dev, "missing platform data\n");
 101                 return -ENODEV;
 102         }
 103 
 104         if (pdata->num_leds > ADP5520_01_MAXLEDS) {
 105                 dev_err(&pdev->dev, "can't handle more than %d LEDS\n",
 106                                  ADP5520_01_MAXLEDS);
 107                 return -EFAULT;
 108         }
 109 
 110         led = devm_kcalloc(&pdev->dev, pdata->num_leds, sizeof(*led),
 111                                 GFP_KERNEL);
 112         if (!led)
 113                 return -ENOMEM;
 114 
 115         ret = adp5520_led_prepare(pdev);
 116         if (ret) {
 117                 dev_err(&pdev->dev, "failed to write\n");
 118                 return ret;
 119         }
 120 
 121         for (i = 0; i < pdata->num_leds; ++i) {
 122                 cur_led = &pdata->leds[i];
 123                 led_dat = &led[i];
 124 
 125                 led_dat->cdev.name = cur_led->name;
 126                 led_dat->cdev.default_trigger = cur_led->default_trigger;
 127                 led_dat->cdev.brightness_set_blocking = adp5520_led_set;
 128                 led_dat->cdev.brightness = LED_OFF;
 129 
 130                 if (cur_led->flags & ADP5520_FLAG_LED_MASK)
 131                         led_dat->flags = cur_led->flags;
 132                 else
 133                         led_dat->flags = i + 1;
 134 
 135                 led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
 136 
 137                 led_dat->master = pdev->dev.parent;
 138 
 139                 ret = led_classdev_register(led_dat->master, &led_dat->cdev);
 140                 if (ret) {
 141                         dev_err(&pdev->dev, "failed to register LED %d\n",
 142                                 led_dat->id);
 143                         goto err;
 144                 }
 145 
 146                 ret = adp5520_led_setup(led_dat);
 147                 if (ret) {
 148                         dev_err(&pdev->dev, "failed to write\n");
 149                         i++;
 150                         goto err;
 151                 }
 152         }
 153 
 154         platform_set_drvdata(pdev, led);
 155         return 0;
 156 
 157 err:
 158         if (i > 0) {
 159                 for (i = i - 1; i >= 0; i--)
 160                         led_classdev_unregister(&led[i].cdev);
 161         }
 162 
 163         return ret;
 164 }
 165 
 166 static int adp5520_led_remove(struct platform_device *pdev)
 167 {
 168         struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
 169         struct adp5520_led *led;
 170         int i;
 171 
 172         led = platform_get_drvdata(pdev);
 173 
 174         adp5520_clr_bits(led->master, ADP5520_LED_CONTROL,
 175                  ADP5520_LED1_EN | ADP5520_LED2_EN | ADP5520_LED3_EN);
 176 
 177         for (i = 0; i < pdata->num_leds; i++) {
 178                 led_classdev_unregister(&led[i].cdev);
 179         }
 180 
 181         return 0;
 182 }
 183 
 184 static struct platform_driver adp5520_led_driver = {
 185         .driver = {
 186                 .name   = "adp5520-led",
 187         },
 188         .probe          = adp5520_led_probe,
 189         .remove         = adp5520_led_remove,
 190 };
 191 
 192 module_platform_driver(adp5520_led_driver);
 193 
 194 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 195 MODULE_DESCRIPTION("LEDS ADP5520(01) Driver");
 196 MODULE_LICENSE("GPL");
 197 MODULE_ALIAS("platform:adp5520-led");

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