cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

leds-adp5520.c (4932B)


      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
     22struct adp5520_led {
     23	struct led_classdev	cdev;
     24	struct device		*master;
     25	int			id;
     26	int			flags;
     27};
     28
     29static 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
     39static 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
     76static 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
     92static 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
    157err:
    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
    166static 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
    184static 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
    192module_platform_driver(adp5520_led_driver);
    193
    194MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
    195MODULE_DESCRIPTION("LEDS ADP5520(01) Driver");
    196MODULE_LICENSE("GPL");
    197MODULE_ALIAS("platform:adp5520-led");