Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (C) 2018 BayLibre SAS
0004 // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
0005 //
0006 // LED driver for MAXIM 77650/77651 charger/power-supply.
0007 
0008 #include <linux/i2c.h>
0009 #include <linux/leds.h>
0010 #include <linux/mfd/max77650.h>
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/regmap.h>
0014 
0015 #define MAX77650_LED_NUM_LEDS       3
0016 
0017 #define MAX77650_LED_A_BASE     0x40
0018 #define MAX77650_LED_B_BASE     0x43
0019 
0020 #define MAX77650_LED_BR_MASK        GENMASK(4, 0)
0021 #define MAX77650_LED_EN_MASK        GENMASK(7, 6)
0022 
0023 #define MAX77650_LED_MAX_BRIGHTNESS MAX77650_LED_BR_MASK
0024 
0025 /* Enable EN_LED_MSTR. */
0026 #define MAX77650_LED_TOP_DEFAULT    BIT(0)
0027 
0028 #define MAX77650_LED_ENABLE     GENMASK(7, 6)
0029 #define MAX77650_LED_DISABLE        0x00
0030 
0031 #define MAX77650_LED_A_DEFAULT      MAX77650_LED_DISABLE
0032 /* 100% on duty */
0033 #define MAX77650_LED_B_DEFAULT      GENMASK(3, 0)
0034 
0035 struct max77650_led {
0036     struct led_classdev cdev;
0037     struct regmap *map;
0038     unsigned int regA;
0039     unsigned int regB;
0040 };
0041 
0042 static struct max77650_led *max77650_to_led(struct led_classdev *cdev)
0043 {
0044     return container_of(cdev, struct max77650_led, cdev);
0045 }
0046 
0047 static int max77650_led_brightness_set(struct led_classdev *cdev,
0048                        enum led_brightness brightness)
0049 {
0050     struct max77650_led *led = max77650_to_led(cdev);
0051     int val, mask;
0052 
0053     mask = MAX77650_LED_BR_MASK | MAX77650_LED_EN_MASK;
0054 
0055     if (brightness == LED_OFF)
0056         val = MAX77650_LED_DISABLE;
0057     else
0058         val = MAX77650_LED_ENABLE | brightness;
0059 
0060     return regmap_update_bits(led->map, led->regA, mask, val);
0061 }
0062 
0063 static int max77650_led_probe(struct platform_device *pdev)
0064 {
0065     struct fwnode_handle *child;
0066     struct max77650_led *leds, *led;
0067     struct device *dev;
0068     struct regmap *map;
0069     int rv, num_leds;
0070     u32 reg;
0071 
0072     dev = &pdev->dev;
0073 
0074     leds = devm_kcalloc(dev, sizeof(*leds),
0075                 MAX77650_LED_NUM_LEDS, GFP_KERNEL);
0076     if (!leds)
0077         return -ENOMEM;
0078 
0079     map = dev_get_regmap(dev->parent, NULL);
0080     if (!map)
0081         return -ENODEV;
0082 
0083     num_leds = device_get_child_node_count(dev);
0084     if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS)
0085         return -ENODEV;
0086 
0087     device_for_each_child_node(dev, child) {
0088         struct led_init_data init_data = {};
0089 
0090         rv = fwnode_property_read_u32(child, "reg", &reg);
0091         if (rv || reg >= MAX77650_LED_NUM_LEDS) {
0092             rv = -EINVAL;
0093             goto err_node_put;
0094         }
0095 
0096         led = &leds[reg];
0097         led->map = map;
0098         led->regA = MAX77650_LED_A_BASE + reg;
0099         led->regB = MAX77650_LED_B_BASE + reg;
0100         led->cdev.brightness_set_blocking = max77650_led_brightness_set;
0101         led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
0102 
0103         init_data.fwnode = child;
0104         init_data.devicename = "max77650";
0105         /* for backwards compatibility if `label` is not present */
0106         init_data.default_label = ":";
0107 
0108         rv = devm_led_classdev_register_ext(dev, &led->cdev,
0109                             &init_data);
0110         if (rv)
0111             goto err_node_put;
0112 
0113         rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT);
0114         if (rv)
0115             goto err_node_put;
0116 
0117         rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT);
0118         if (rv)
0119             goto err_node_put;
0120     }
0121 
0122     return regmap_write(map,
0123                 MAX77650_REG_CNFG_LED_TOP,
0124                 MAX77650_LED_TOP_DEFAULT);
0125 err_node_put:
0126     fwnode_handle_put(child);
0127     return rv;
0128 }
0129 
0130 static const struct of_device_id max77650_led_of_match[] = {
0131     { .compatible = "maxim,max77650-led" },
0132     { }
0133 };
0134 MODULE_DEVICE_TABLE(of, max77650_led_of_match);
0135 
0136 static struct platform_driver max77650_led_driver = {
0137     .driver = {
0138         .name = "max77650-led",
0139         .of_match_table = max77650_led_of_match,
0140     },
0141     .probe = max77650_led_probe,
0142 };
0143 module_platform_driver(max77650_led_driver);
0144 
0145 MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver");
0146 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
0147 MODULE_LICENSE("GPL v2");
0148 MODULE_ALIAS("platform:max77650-led");