mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
3192f14124
The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring <robh@kernel.org> Link: https://lore.kernel.org/r/20230714174651.4058753-1-robh@kernel.org Signed-off-by: Lee Jones <lee@kernel.org>
183 lines
4.2 KiB
C
183 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* Copyright (c) 2010, 2011, 2016 The Linux Foundation. All rights reserved.
|
|
*/
|
|
#include <linux/leds.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#define PM8058_LED_TYPE_COMMON 0x00
|
|
#define PM8058_LED_TYPE_KEYPAD 0x01
|
|
#define PM8058_LED_TYPE_FLASH 0x02
|
|
|
|
#define PM8058_LED_TYPE_COMMON_MASK 0xf8
|
|
#define PM8058_LED_TYPE_KEYPAD_MASK 0xf0
|
|
#define PM8058_LED_TYPE_COMMON_SHIFT 3
|
|
#define PM8058_LED_TYPE_KEYPAD_SHIFT 4
|
|
|
|
struct pm8058_led {
|
|
struct regmap *map;
|
|
u32 reg;
|
|
u32 ledtype;
|
|
struct led_classdev cdev;
|
|
};
|
|
|
|
static void pm8058_led_set(struct led_classdev *cled,
|
|
enum led_brightness value)
|
|
{
|
|
struct pm8058_led *led;
|
|
int ret = 0;
|
|
unsigned int mask = 0;
|
|
unsigned int val = 0;
|
|
|
|
led = container_of(cled, struct pm8058_led, cdev);
|
|
switch (led->ledtype) {
|
|
case PM8058_LED_TYPE_COMMON:
|
|
mask = PM8058_LED_TYPE_COMMON_MASK;
|
|
val = value << PM8058_LED_TYPE_COMMON_SHIFT;
|
|
break;
|
|
case PM8058_LED_TYPE_KEYPAD:
|
|
case PM8058_LED_TYPE_FLASH:
|
|
mask = PM8058_LED_TYPE_KEYPAD_MASK;
|
|
val = value << PM8058_LED_TYPE_KEYPAD_SHIFT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ret = regmap_update_bits(led->map, led->reg, mask, val);
|
|
if (ret)
|
|
pr_err("Failed to set LED brightness\n");
|
|
}
|
|
|
|
static enum led_brightness pm8058_led_get(struct led_classdev *cled)
|
|
{
|
|
struct pm8058_led *led;
|
|
int ret;
|
|
unsigned int val;
|
|
|
|
led = container_of(cled, struct pm8058_led, cdev);
|
|
|
|
ret = regmap_read(led->map, led->reg, &val);
|
|
if (ret) {
|
|
pr_err("Failed to get LED brightness\n");
|
|
return LED_OFF;
|
|
}
|
|
|
|
switch (led->ledtype) {
|
|
case PM8058_LED_TYPE_COMMON:
|
|
val &= PM8058_LED_TYPE_COMMON_MASK;
|
|
val >>= PM8058_LED_TYPE_COMMON_SHIFT;
|
|
break;
|
|
case PM8058_LED_TYPE_KEYPAD:
|
|
case PM8058_LED_TYPE_FLASH:
|
|
val &= PM8058_LED_TYPE_KEYPAD_MASK;
|
|
val >>= PM8058_LED_TYPE_KEYPAD_SHIFT;
|
|
break;
|
|
default:
|
|
val = LED_OFF;
|
|
break;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static int pm8058_led_probe(struct platform_device *pdev)
|
|
{
|
|
struct led_init_data init_data = {};
|
|
struct device *dev = &pdev->dev;
|
|
struct pm8058_led *led;
|
|
struct device_node *np;
|
|
int ret;
|
|
struct regmap *map;
|
|
enum led_brightness maxbright;
|
|
enum led_default_state state;
|
|
|
|
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
|
|
if (!led)
|
|
return -ENOMEM;
|
|
|
|
led->ledtype = (u32)(unsigned long)of_device_get_match_data(dev);
|
|
|
|
map = dev_get_regmap(dev->parent, NULL);
|
|
if (!map) {
|
|
dev_err(dev, "Parent regmap unavailable.\n");
|
|
return -ENXIO;
|
|
}
|
|
led->map = map;
|
|
|
|
np = dev_of_node(dev);
|
|
|
|
ret = of_property_read_u32(np, "reg", &led->reg);
|
|
if (ret) {
|
|
dev_err(dev, "no register offset specified\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
led->cdev.brightness_set = pm8058_led_set;
|
|
led->cdev.brightness_get = pm8058_led_get;
|
|
if (led->ledtype == PM8058_LED_TYPE_COMMON)
|
|
maxbright = 31; /* 5 bits */
|
|
else
|
|
maxbright = 15; /* 4 bits */
|
|
led->cdev.max_brightness = maxbright;
|
|
|
|
init_data.fwnode = of_fwnode_handle(np);
|
|
|
|
state = led_init_default_state_get(init_data.fwnode);
|
|
switch (state) {
|
|
case LEDS_DEFSTATE_ON:
|
|
led->cdev.brightness = maxbright;
|
|
pm8058_led_set(&led->cdev, maxbright);
|
|
break;
|
|
case LEDS_DEFSTATE_KEEP:
|
|
led->cdev.brightness = pm8058_led_get(&led->cdev);
|
|
break;
|
|
default:
|
|
led->cdev.brightness = LED_OFF;
|
|
pm8058_led_set(&led->cdev, LED_OFF);
|
|
}
|
|
|
|
if (led->ledtype == PM8058_LED_TYPE_KEYPAD ||
|
|
led->ledtype == PM8058_LED_TYPE_FLASH)
|
|
led->cdev.flags = LED_CORE_SUSPENDRESUME;
|
|
|
|
ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
|
|
if (ret)
|
|
dev_err(dev, "Failed to register LED for %pOF\n", np);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct of_device_id pm8058_leds_id_table[] = {
|
|
{
|
|
.compatible = "qcom,pm8058-led",
|
|
.data = (void *)PM8058_LED_TYPE_COMMON
|
|
},
|
|
{
|
|
.compatible = "qcom,pm8058-keypad-led",
|
|
.data = (void *)PM8058_LED_TYPE_KEYPAD
|
|
},
|
|
{
|
|
.compatible = "qcom,pm8058-flash-led",
|
|
.data = (void *)PM8058_LED_TYPE_FLASH
|
|
},
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(of, pm8058_leds_id_table);
|
|
|
|
static struct platform_driver pm8058_led_driver = {
|
|
.probe = pm8058_led_probe,
|
|
.driver = {
|
|
.name = "pm8058-leds",
|
|
.of_match_table = pm8058_leds_id_table,
|
|
},
|
|
};
|
|
module_platform_driver(pm8058_led_driver);
|
|
|
|
MODULE_DESCRIPTION("PM8058 LEDs driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_ALIAS("platform:pm8058-leds");
|