blob: e469c22574e31148a9edd78cf306a2dba5ce1808 [file] [log] [blame]
Jonas Remmert99751b12023-05-29 23:04:48 +02001/*
2 * Copyright (c) 2023 Phytec Messtechnik GmbH.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#define DT_DRV_COMPAT ti_lp5569
8
9/**
10 * @file
11 * @brief LP5569 LED controller
12 *
13 * The LP5569 is a 9-channel LED driver that communicates over I2C.
14 */
15
16#include <zephyr/drivers/i2c.h>
17#include <zephyr/drivers/led.h>
18#include <zephyr/device.h>
Jonas Remmert49707df2023-05-29 23:08:16 +020019#include <zephyr/pm/device.h>
Jonas Remmert99751b12023-05-29 23:04:48 +020020#include <zephyr/kernel.h>
21
22#include <zephyr/logging/log.h>
23LOG_MODULE_REGISTER(lp5569, CONFIG_LED_LOG_LEVEL);
24
25#define LP5569_NUM_LEDS 9
26
27/* General Registers */
28#define LP5569_CONFIG 0x00
29#define LP5569_CHIP_EN BIT(6)
30
31#define LP5569_MISC 0x2F
32#define LP5569_POWERSAVE_EN BIT(5)
33
34/* PWM base Register for controlling the duty-cycle */
35#define LP5569_LED0_PWM 0x16
36
37struct lp5569_config {
38 struct i2c_dt_spec bus;
39};
40
41static int lp5569_led_set_brightness(const struct device *dev, uint32_t led,
42 uint8_t brightness)
43{
44 const struct lp5569_config *config = dev->config;
45 uint8_t val;
46 int ret;
47
48 if (led >= LP5569_NUM_LEDS || brightness > 100) {
49 return -EINVAL;
50 }
51
52 /* Map 0-100 % to 0-255 pwm register value */
53 val = brightness * 255 / 100;
54
55 ret = i2c_reg_write_byte_dt(&config->bus, LP5569_LED0_PWM + led, val);
56 if (ret < 0) {
57 LOG_ERR("LED reg update failed");
58 return ret;
59 }
60
61 return 0;
62}
63
64static inline int lp5569_led_on(const struct device *dev, uint32_t led)
65{
66 /* Set LED brightness to 100 % */
67 return lp5569_led_set_brightness(dev, led, 100);
68}
69
70static inline int lp5569_led_off(const struct device *dev, uint32_t led)
71{
72 /* Set LED brightness to 0 % */
73 return lp5569_led_set_brightness(dev, led, 0);
74}
75
Jonas Remmert49707df2023-05-29 23:08:16 +020076static int lp5569_enable(const struct device *dev)
Jonas Remmert99751b12023-05-29 23:04:48 +020077{
78 const struct lp5569_config *config = dev->config;
79 int ret;
80
81 if (!i2c_is_ready_dt(&config->bus)) {
82 LOG_ERR("I2C device not ready");
83 return -ENODEV;
84 }
85
86 ret = i2c_reg_write_byte_dt(&config->bus, LP5569_CONFIG,
87 LP5569_CHIP_EN);
88 if (ret < 0) {
89 LOG_ERR("Enable LP5569 failed");
90 return ret;
91 }
92
93 ret = i2c_reg_write_byte_dt(&config->bus, LP5569_MISC,
94 LP5569_POWERSAVE_EN);
95 if (ret < 0) {
96 LOG_ERR("LED reg update failed");
97 return ret;
98 }
99
100 return 0;
101}
102
Jonas Remmert49707df2023-05-29 23:08:16 +0200103static int lp5569_init(const struct device *dev)
104{
105 /* If the device is behind a power domain, it will start in
106 * PM_DEVICE_STATE_OFF.
107 */
108 if (pm_device_on_power_domain(dev)) {
109 pm_device_init_off(dev);
110 LOG_INF("Init %s as PM_DEVICE_STATE_OFF", dev->name);
111 return 0;
112 }
113
114 return lp5569_enable(dev);
115}
116
117#ifdef CONFIG_PM_DEVICE
118static int lp5569_pm_action(const struct device *dev,
119 enum pm_device_action action)
120{
121 const struct lp5569_config *config = dev->config;
122 int ret;
123
124 switch (action) {
125 case PM_DEVICE_ACTION_TURN_ON:
126 case PM_DEVICE_ACTION_RESUME:
127 ret = lp5569_enable(dev);
128 if (ret < 0) {
129 LOG_ERR("Enable LP5569 failed");
130 return ret;
131 }
132 break;
133 case PM_DEVICE_ACTION_TURN_OFF:
134 case PM_DEVICE_ACTION_SUSPEND:
135 ret = i2c_reg_update_byte_dt(&config->bus, LP5569_CONFIG,
136 LP5569_CHIP_EN, 0);
137 if (ret < 0) {
138 LOG_ERR("Disable LP5569 failed");
139 return ret;
140 }
141 break;
142 default:
143 return -ENOTSUP;
144 }
145
146 return 0;
147}
148#endif /* CONFIG_PM_DEVICE */
Jonas Remmert99751b12023-05-29 23:04:48 +0200149
150static const struct led_driver_api lp5569_led_api = {
151 .set_brightness = lp5569_led_set_brightness,
152 .on = lp5569_led_on,
153 .off = lp5569_led_off,
154};
155
156#define LP5569_DEFINE(id) \
157 static const struct lp5569_config lp5569_config_##id = { \
158 .bus = I2C_DT_SPEC_INST_GET(id), \
159 }; \
160 \
Jonas Remmert49707df2023-05-29 23:08:16 +0200161 PM_DEVICE_DT_INST_DEFINE(id, lp5569_pm_action); \
162 \
Jonas Remmert99751b12023-05-29 23:04:48 +0200163 DEVICE_DT_INST_DEFINE(id, &lp5569_init, \
Jonas Remmert49707df2023-05-29 23:08:16 +0200164 PM_DEVICE_DT_INST_GET(id), \
Jonas Remmert99751b12023-05-29 23:04:48 +0200165 NULL, \
166 &lp5569_config_##id, POST_KERNEL, \
167 CONFIG_LED_INIT_PRIORITY, \
168 &lp5569_led_api);
169
170DT_INST_FOREACH_STATUS_OKAY(LP5569_DEFINE)