183 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2010, 2011, 2016 The Linux Foundation. All rights reserved.3 */4#include <linux/leds.h>5#include <linux/module.h>6#include <linux/of.h>7#include <linux/platform_device.h>8#include <linux/pm.h>9#include <linux/regmap.h>10 11#define PM8058_LED_TYPE_COMMON 0x0012#define PM8058_LED_TYPE_KEYPAD 0x0113#define PM8058_LED_TYPE_FLASH 0x0214 15#define PM8058_LED_TYPE_COMMON_MASK 0xf816#define PM8058_LED_TYPE_KEYPAD_MASK 0xf017#define PM8058_LED_TYPE_COMMON_SHIFT 318#define PM8058_LED_TYPE_KEYPAD_SHIFT 419 20struct pm8058_led {21 struct regmap *map;22 u32 reg;23 u32 ledtype;24 struct led_classdev cdev;25};26 27static void pm8058_led_set(struct led_classdev *cled,28 enum led_brightness value)29{30 struct pm8058_led *led;31 int ret = 0;32 unsigned int mask = 0;33 unsigned int val = 0;34 35 led = container_of(cled, struct pm8058_led, cdev);36 switch (led->ledtype) {37 case PM8058_LED_TYPE_COMMON:38 mask = PM8058_LED_TYPE_COMMON_MASK;39 val = value << PM8058_LED_TYPE_COMMON_SHIFT;40 break;41 case PM8058_LED_TYPE_KEYPAD:42 case PM8058_LED_TYPE_FLASH:43 mask = PM8058_LED_TYPE_KEYPAD_MASK;44 val = value << PM8058_LED_TYPE_KEYPAD_SHIFT;45 break;46 default:47 break;48 }49 50 ret = regmap_update_bits(led->map, led->reg, mask, val);51 if (ret)52 pr_err("Failed to set LED brightness\n");53}54 55static enum led_brightness pm8058_led_get(struct led_classdev *cled)56{57 struct pm8058_led *led;58 int ret;59 unsigned int val;60 61 led = container_of(cled, struct pm8058_led, cdev);62 63 ret = regmap_read(led->map, led->reg, &val);64 if (ret) {65 pr_err("Failed to get LED brightness\n");66 return LED_OFF;67 }68 69 switch (led->ledtype) {70 case PM8058_LED_TYPE_COMMON:71 val &= PM8058_LED_TYPE_COMMON_MASK;72 val >>= PM8058_LED_TYPE_COMMON_SHIFT;73 break;74 case PM8058_LED_TYPE_KEYPAD:75 case PM8058_LED_TYPE_FLASH:76 val &= PM8058_LED_TYPE_KEYPAD_MASK;77 val >>= PM8058_LED_TYPE_KEYPAD_SHIFT;78 break;79 default:80 val = LED_OFF;81 break;82 }83 84 return val;85}86 87static int pm8058_led_probe(struct platform_device *pdev)88{89 struct led_init_data init_data = {};90 struct device *dev = &pdev->dev;91 struct pm8058_led *led;92 struct device_node *np;93 int ret;94 struct regmap *map;95 enum led_brightness maxbright;96 enum led_default_state state;97 98 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);99 if (!led)100 return -ENOMEM;101 102 led->ledtype = (u32)(unsigned long)of_device_get_match_data(dev);103 104 map = dev_get_regmap(dev->parent, NULL);105 if (!map) {106 dev_err(dev, "Parent regmap unavailable.\n");107 return -ENXIO;108 }109 led->map = map;110 111 np = dev_of_node(dev);112 113 ret = of_property_read_u32(np, "reg", &led->reg);114 if (ret) {115 dev_err(dev, "no register offset specified\n");116 return -EINVAL;117 }118 119 led->cdev.brightness_set = pm8058_led_set;120 led->cdev.brightness_get = pm8058_led_get;121 if (led->ledtype == PM8058_LED_TYPE_COMMON)122 maxbright = 31; /* 5 bits */123 else124 maxbright = 15; /* 4 bits */125 led->cdev.max_brightness = maxbright;126 127 init_data.fwnode = of_fwnode_handle(np);128 129 state = led_init_default_state_get(init_data.fwnode);130 switch (state) {131 case LEDS_DEFSTATE_ON:132 led->cdev.brightness = maxbright;133 pm8058_led_set(&led->cdev, maxbright);134 break;135 case LEDS_DEFSTATE_KEEP:136 led->cdev.brightness = pm8058_led_get(&led->cdev);137 break;138 default:139 led->cdev.brightness = LED_OFF;140 pm8058_led_set(&led->cdev, LED_OFF);141 }142 143 if (led->ledtype == PM8058_LED_TYPE_KEYPAD ||144 led->ledtype == PM8058_LED_TYPE_FLASH)145 led->cdev.flags = LED_CORE_SUSPENDRESUME;146 147 ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);148 if (ret)149 dev_err(dev, "Failed to register LED for %pOF\n", np);150 151 return ret;152}153 154static const struct of_device_id pm8058_leds_id_table[] = {155 {156 .compatible = "qcom,pm8058-led",157 .data = (void *)PM8058_LED_TYPE_COMMON158 },159 {160 .compatible = "qcom,pm8058-keypad-led",161 .data = (void *)PM8058_LED_TYPE_KEYPAD162 },163 {164 .compatible = "qcom,pm8058-flash-led",165 .data = (void *)PM8058_LED_TYPE_FLASH166 },167 { },168};169MODULE_DEVICE_TABLE(of, pm8058_leds_id_table);170 171static struct platform_driver pm8058_led_driver = {172 .probe = pm8058_led_probe,173 .driver = {174 .name = "pm8058-leds",175 .of_match_table = pm8058_leds_id_table,176 },177};178module_platform_driver(pm8058_led_driver);179 180MODULE_DESCRIPTION("PM8058 LEDs driver");181MODULE_LICENSE("GPL v2");182MODULE_ALIAS("platform:pm8058-leds");183