Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * LEDs driver for Dialog Semiconductor DA9030/DA9034
0004  *
0005  * Copyright (C) 2008 Compulab, Ltd.
0006  *  Mike Rapoport <mike@compulab.co.il>
0007  *
0008  * Copyright (C) 2006-2008 Marvell International Ltd.
0009  *  Eric Miao <eric.miao@marvell.com>
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/leds.h>
0016 #include <linux/mfd/da903x.h>
0017 #include <linux/slab.h>
0018 
0019 #define DA9030_LED1_CONTROL 0x20
0020 #define DA9030_LED2_CONTROL 0x21
0021 #define DA9030_LED3_CONTROL 0x22
0022 #define DA9030_LED4_CONTROL 0x23
0023 #define DA9030_LEDPC_CONTROL    0x24
0024 #define DA9030_MISC_CONTROL_A   0x26    /* Vibrator Control */
0025 
0026 #define DA9034_LED1_CONTROL 0x35
0027 #define DA9034_LED2_CONTROL 0x36
0028 #define DA9034_VIBRA        0x40
0029 
0030 struct da903x_led {
0031     struct led_classdev cdev;
0032     struct device       *master;
0033     int         id;
0034     int         flags;
0035 };
0036 
0037 #define DA9030_LED_OFFSET(id)   ((id) - DA9030_ID_LED_1)
0038 #define DA9034_LED_OFFSET(id)   ((id) - DA9034_ID_LED_1)
0039 
0040 static int da903x_led_set(struct led_classdev *led_cdev,
0041                enum led_brightness value)
0042 {
0043     struct da903x_led *led =
0044             container_of(led_cdev, struct da903x_led, cdev);
0045     uint8_t val;
0046     int offset, ret = -EINVAL;
0047 
0048     switch (led->id) {
0049     case DA9030_ID_LED_1:
0050     case DA9030_ID_LED_2:
0051     case DA9030_ID_LED_3:
0052     case DA9030_ID_LED_4:
0053     case DA9030_ID_LED_PC:
0054         offset = DA9030_LED_OFFSET(led->id);
0055         val = led->flags & ~0x87;
0056         val |= value ? 0x80 : 0; /* EN bit */
0057         val |= (0x7 - (value >> 5)) & 0x7; /* PWM<2:0> */
0058         ret = da903x_write(led->master, DA9030_LED1_CONTROL + offset,
0059                    val);
0060         break;
0061     case DA9030_ID_VIBRA:
0062         val = led->flags & ~0x80;
0063         val |= value ? 0x80 : 0; /* EN bit */
0064         ret = da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
0065         break;
0066     case DA9034_ID_LED_1:
0067     case DA9034_ID_LED_2:
0068         offset = DA9034_LED_OFFSET(led->id);
0069         val = (value * 0x5f / LED_FULL) & 0x7f;
0070         val |= (led->flags & DA9034_LED_RAMP) ? 0x80 : 0;
0071         ret = da903x_write(led->master, DA9034_LED1_CONTROL + offset,
0072                    val);
0073         break;
0074     case DA9034_ID_VIBRA:
0075         val = value & 0xfe;
0076         ret = da903x_write(led->master, DA9034_VIBRA, val);
0077         break;
0078     }
0079 
0080     return ret;
0081 }
0082 
0083 static int da903x_led_probe(struct platform_device *pdev)
0084 {
0085     struct led_info *pdata = dev_get_platdata(&pdev->dev);
0086     struct da903x_led *led;
0087     int id, ret;
0088 
0089     if (pdata == NULL)
0090         return 0;
0091 
0092     id = pdev->id;
0093 
0094     if (!((id >= DA9030_ID_LED_1 && id <= DA9030_ID_VIBRA) ||
0095           (id >= DA9034_ID_LED_1 && id <= DA9034_ID_VIBRA))) {
0096         dev_err(&pdev->dev, "invalid LED ID (%d) specified\n", id);
0097         return -EINVAL;
0098     }
0099 
0100     led = devm_kzalloc(&pdev->dev, sizeof(struct da903x_led), GFP_KERNEL);
0101     if (!led)
0102         return -ENOMEM;
0103 
0104     led->cdev.name = pdata->name;
0105     led->cdev.default_trigger = pdata->default_trigger;
0106     led->cdev.brightness_set_blocking = da903x_led_set;
0107     led->cdev.brightness = LED_OFF;
0108 
0109     led->id = id;
0110     led->flags = pdata->flags;
0111     led->master = pdev->dev.parent;
0112 
0113     ret = led_classdev_register(led->master, &led->cdev);
0114     if (ret) {
0115         dev_err(&pdev->dev, "failed to register LED %d\n", id);
0116         return ret;
0117     }
0118 
0119     platform_set_drvdata(pdev, led);
0120 
0121     return 0;
0122 }
0123 
0124 static int da903x_led_remove(struct platform_device *pdev)
0125 {
0126     struct da903x_led *led = platform_get_drvdata(pdev);
0127 
0128     led_classdev_unregister(&led->cdev);
0129 
0130     return 0;
0131 }
0132 
0133 static struct platform_driver da903x_led_driver = {
0134     .driver = {
0135         .name   = "da903x-led",
0136     },
0137     .probe      = da903x_led_probe,
0138     .remove     = da903x_led_remove,
0139 };
0140 
0141 module_platform_driver(da903x_led_driver);
0142 
0143 MODULE_DESCRIPTION("LEDs driver for Dialog Semiconductor DA9030/DA9034");
0144 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
0145 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
0146 MODULE_LICENSE("GPL");
0147 MODULE_ALIAS("platform:da903x-led");