Blame view

drivers/leds/leds-pm8058.c 4.23 KB
97fb5e8d9   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
7f866986e   Linus Walleij   leds: add PM8058 ...
2
  /* Copyright (c) 2010, 2011, 2016 The Linux Foundation. All rights reserved.
7f866986e   Linus Walleij   leds: add PM8058 ...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
   */
  #include <linux/leds.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/of_device.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
  ");
  }
  
  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
  ");
  		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)
  {
eed951bbf   Marek Behún   leds: pm8058: use...
92
  	struct led_init_data init_data = {};
fb270ba0d   Marek Behún   leds: pm8058: cos...
93
  	struct device *dev = &pdev->dev;
7f866986e   Linus Walleij   leds: add PM8058 ...
94
  	struct pm8058_led *led;
fb270ba0d   Marek Behún   leds: pm8058: cos...
95
  	struct device_node *np;
7f866986e   Linus Walleij   leds: add PM8058 ...
96
97
98
99
  	int ret;
  	struct regmap *map;
  	const char *state;
  	enum led_brightness maxbright;
fb270ba0d   Marek Behún   leds: pm8058: cos...
100
  	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
7f866986e   Linus Walleij   leds: add PM8058 ...
101
102
  	if (!led)
  		return -ENOMEM;
fb270ba0d   Marek Behún   leds: pm8058: cos...
103
  	led->ledtype = (u32)(unsigned long)of_device_get_match_data(dev);
7f866986e   Linus Walleij   leds: add PM8058 ...
104

fb270ba0d   Marek Behún   leds: pm8058: cos...
105
  	map = dev_get_regmap(dev->parent, NULL);
7f866986e   Linus Walleij   leds: add PM8058 ...
106
  	if (!map) {
fb270ba0d   Marek Behún   leds: pm8058: cos...
107
108
  		dev_err(dev, "Parent regmap unavailable.
  ");
7f866986e   Linus Walleij   leds: add PM8058 ...
109
110
111
  		return -ENXIO;
  	}
  	led->map = map;
fb270ba0d   Marek Behún   leds: pm8058: cos...
112
  	np = dev_of_node(dev);
7f866986e   Linus Walleij   leds: add PM8058 ...
113
114
  	ret = of_property_read_u32(np, "reg", &led->reg);
  	if (ret) {
fb270ba0d   Marek Behún   leds: pm8058: cos...
115
116
  		dev_err(dev, "no register offset specified
  ");
7f866986e   Linus Walleij   leds: add PM8058 ...
117
118
  		return -EINVAL;
  	}
7f866986e   Linus Walleij   leds: add PM8058 ...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	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;
  
  	state = of_get_property(np, "default-state", NULL);
  	if (state) {
  		if (!strcmp(state, "keep")) {
  			led->cdev.brightness = pm8058_led_get(&led->cdev);
  		} else if (!strcmp(state, "on")) {
  			led->cdev.brightness = maxbright;
  			pm8058_led_set(&led->cdev, maxbright);
  		} else {
  			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;
eed951bbf   Marek Behún   leds: pm8058: use...
143
  	init_data.fwnode = of_fwnode_handle(np);
fb270ba0d   Marek Behún   leds: pm8058: cos...
144
  	ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
1016daf98   Marek Behún   leds: pm8058: cos...
145
  	if (ret)
fb270ba0d   Marek Behún   leds: pm8058: cos...
146
147
  		dev_err(dev, "Failed to register LED for %pOF
  ", np);
7f866986e   Linus Walleij   leds: add PM8058 ...
148

1016daf98   Marek Behún   leds: pm8058: cos...
149
  	return ret;
7f866986e   Linus Walleij   leds: add PM8058 ...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  }
  
  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");