Blame view

drivers/leds/leds-lm36274.c 4.14 KB
11e1bbc11   Dan Murphy   leds: lm36274: In...
1
2
  // SPDX-License-Identifier: GPL-2.0
  // TI LM36274 LED chip family driver
c54373381   Alexander A. Klimov   leds: Replace HTT...
3
  // Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
11e1bbc11   Dan Murphy   leds: lm36274: In...
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
  
  #include <linux/bitops.h>
  #include <linux/device.h>
  #include <linux/err.h>
  #include <linux/leds.h>
  #include <linux/leds-ti-lmu-common.h>
  #include <linux/module.h>
  #include <linux/of_device.h>
  #include <linux/platform_device.h>
  
  #include <linux/mfd/ti-lmu.h>
  #include <linux/mfd/ti-lmu-register.h>
  
  #include <uapi/linux/uleds.h>
  
  #define LM36274_MAX_STRINGS	4
  #define LM36274_BL_EN		BIT(4)
  
  /**
   * struct lm36274
   * @pdev: platform device
   * @led_dev: led class device
   * @lmu_data: Register and setting values for common code
   * @regmap: Devices register map
   * @dev: Pointer to the devices device struct
9adc8af4c   Dan Murphy   leds: lm36274: Fi...
29
30
   * @led_sources: The LED strings supported in this array
   * @num_leds: Number of LED strings are supported in this array
11e1bbc11   Dan Murphy   leds: lm36274: In...
31
32
33
34
35
36
37
38
39
40
41
42
43
   */
  struct lm36274 {
  	struct platform_device *pdev;
  	struct led_classdev led_dev;
  	struct ti_lmu_bank lmu_data;
  	struct regmap *regmap;
  	struct device *dev;
  
  	u32 led_sources[LM36274_MAX_STRINGS];
  	int num_leds;
  };
  
  static int lm36274_brightness_set(struct led_classdev *led_cdev,
d3ab963cf   Marek Behún   leds: lm36274: co...
44
  				  enum led_brightness brt_val)
11e1bbc11   Dan Murphy   leds: lm36274: In...
45
  {
d3ab963cf   Marek Behún   leds: lm36274: co...
46
  	struct lm36274 *chip = container_of(led_cdev, struct lm36274, led_dev);
11e1bbc11   Dan Murphy   leds: lm36274: In...
47

d3ab963cf   Marek Behún   leds: lm36274: co...
48
  	return ti_lmu_common_set_brightness(&chip->lmu_data, brt_val);
11e1bbc11   Dan Murphy   leds: lm36274: In...
49
  }
d3ab963cf   Marek Behún   leds: lm36274: co...
50
  static int lm36274_init(struct lm36274 *chip)
11e1bbc11   Dan Murphy   leds: lm36274: In...
51
52
53
  {
  	int enable_val = 0;
  	int i;
d3ab963cf   Marek Behún   leds: lm36274: co...
54
55
  	for (i = 0; i < chip->num_leds; i++)
  		enable_val |= (1 << chip->led_sources[i]);
11e1bbc11   Dan Murphy   leds: lm36274: In...
56
57
  
  	if (!enable_val) {
d3ab963cf   Marek Behún   leds: lm36274: co...
58
59
  		dev_err(chip->dev, "No LEDs were enabled
  ");
11e1bbc11   Dan Murphy   leds: lm36274: In...
60
61
62
63
  		return -EINVAL;
  	}
  
  	enable_val |= LM36274_BL_EN;
d3ab963cf   Marek Behún   leds: lm36274: co...
64
  	return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val);
11e1bbc11   Dan Murphy   leds: lm36274: In...
65
  }
1aeef38c6   Marek Behún   leds: lm36274: us...
66
67
  static int lm36274_parse_dt(struct lm36274 *chip,
  			    struct led_init_data *init_data)
11e1bbc11   Dan Murphy   leds: lm36274: In...
68
  {
5c0d20a96   Marek Behún   leds: lm36274: us...
69
  	struct device *dev = chip->dev;
1aeef38c6   Marek Behún   leds: lm36274: us...
70
  	struct fwnode_handle *child;
a448fcf19   Marek Behún   leds: lm36274: do...
71
  	int ret;
11e1bbc11   Dan Murphy   leds: lm36274: In...
72
73
  
  	/* There should only be 1 node */
a448fcf19   Marek Behún   leds: lm36274: do...
74
  	if (device_get_child_node_count(dev) != 1)
11e1bbc11   Dan Murphy   leds: lm36274: In...
75
  		return -EINVAL;
a448fcf19   Marek Behún   leds: lm36274: do...
76
  	child = device_get_next_child_node(dev, NULL);
1aeef38c6   Marek Behún   leds: lm36274: us...
77
78
79
80
  	init_data->fwnode = child;
  	init_data->devicename = chip->pdev->name;
  	/* for backwards compatibility when `label` property is not present */
  	init_data->default_label = ":";
a448fcf19   Marek Behún   leds: lm36274: do...
81
82
  
  	chip->num_leds = fwnode_property_count_u32(child, "led-sources");
1aeef38c6   Marek Behún   leds: lm36274: us...
83
84
85
86
  	if (chip->num_leds <= 0) {
  		ret = -ENODEV;
  		goto err;
  	}
11e1bbc11   Dan Murphy   leds: lm36274: In...
87

a448fcf19   Marek Behún   leds: lm36274: do...
88
89
90
91
92
  	ret = fwnode_property_read_u32_array(child, "led-sources",
  					     chip->led_sources, chip->num_leds);
  	if (ret) {
  		dev_err(dev, "led-sources property missing
  ");
1aeef38c6   Marek Behún   leds: lm36274: us...
93
  		goto err;
11e1bbc11   Dan Murphy   leds: lm36274: In...
94
  	}
11e1bbc11   Dan Murphy   leds: lm36274: In...
95
  	return 0;
1aeef38c6   Marek Behún   leds: lm36274: us...
96
97
98
  err:
  	fwnode_handle_put(child);
  	return ret;
11e1bbc11   Dan Murphy   leds: lm36274: In...
99
100
101
102
103
  }
  
  static int lm36274_probe(struct platform_device *pdev)
  {
  	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
1aeef38c6   Marek Behún   leds: lm36274: us...
104
  	struct led_init_data init_data = {};
d3ab963cf   Marek Behún   leds: lm36274: co...
105
  	struct lm36274 *chip;
11e1bbc11   Dan Murphy   leds: lm36274: In...
106
  	int ret;
d3ab963cf   Marek Behún   leds: lm36274: co...
107
108
  	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
  	if (!chip)
11e1bbc11   Dan Murphy   leds: lm36274: In...
109
  		return -ENOMEM;
d3ab963cf   Marek Behún   leds: lm36274: co...
110
  	chip->pdev = pdev;
5c0d20a96   Marek Behún   leds: lm36274: us...
111
  	chip->dev = &pdev->dev;
d3ab963cf   Marek Behún   leds: lm36274: co...
112
113
  	chip->regmap = lmu->regmap;
  	platform_set_drvdata(pdev, chip);
11e1bbc11   Dan Murphy   leds: lm36274: In...
114

1aeef38c6   Marek Behún   leds: lm36274: us...
115
  	ret = lm36274_parse_dt(chip, &init_data);
11e1bbc11   Dan Murphy   leds: lm36274: In...
116
  	if (ret) {
d3ab963cf   Marek Behún   leds: lm36274: co...
117
118
  		dev_err(chip->dev, "Failed to parse DT node
  ");
11e1bbc11   Dan Murphy   leds: lm36274: In...
119
120
  		return ret;
  	}
d3ab963cf   Marek Behún   leds: lm36274: co...
121
  	ret = lm36274_init(chip);
11e1bbc11   Dan Murphy   leds: lm36274: In...
122
  	if (ret) {
d3ab963cf   Marek Behún   leds: lm36274: co...
123
124
  		dev_err(chip->dev, "Failed to init the device
  ");
11e1bbc11   Dan Murphy   leds: lm36274: In...
125
126
  		return ret;
  	}
484456712   Marek Behún   leds: lm36274: do...
127
128
129
130
131
132
133
  	chip->lmu_data.regmap = chip->regmap;
  	chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
  	chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
  	chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
  
  	chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
  	chip->led_dev.brightness_set_blocking = lm36274_brightness_set;
60bbd9d41   Marek Behún   leds: lm36274: us...
134
135
  	ret = devm_led_classdev_register_ext(chip->dev, &chip->led_dev,
  					     &init_data);
1aeef38c6   Marek Behún   leds: lm36274: us...
136
137
138
139
140
141
142
143
  	if (ret)
  		dev_err(chip->dev, "Failed to register LED for node %pfw
  ",
  			init_data.fwnode);
  
  	fwnode_handle_put(init_data.fwnode);
  
  	return ret;
a0972fff0   Johan Hovold   leds: lm36274: fi...
144
  }
11e1bbc11   Dan Murphy   leds: lm36274: In...
145
146
147
148
149
150
151
152
153
154
  static const struct of_device_id of_lm36274_leds_match[] = {
  	{ .compatible = "ti,lm36274-backlight", },
  	{},
  };
  MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
  
  static struct platform_driver lm36274_driver = {
  	.probe  = lm36274_probe,
  	.driver = {
  		.name = "lm36274-leds",
9adc8af4c   Dan Murphy   leds: lm36274: Fi...
155
  		.of_match_table = of_lm36274_leds_match,
11e1bbc11   Dan Murphy   leds: lm36274: In...
156
157
158
159
160
161
162
  	},
  };
  module_platform_driver(lm36274_driver)
  
  MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver");
  MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
  MODULE_LICENSE("GPL v2");