1ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/*
2ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo * LP5562 LED driver
3ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo *
4ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo * Copyright (C) 2013 Texas Instruments
5ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo *
6ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
7ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo *
8ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo * This program is free software; you can redistribute it and/or modify
9ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo * it under the terms of the GNU General Public License version 2 as
10ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo * published by the Free Software Foundation.
11ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo */
12ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
13ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/delay.h>
14ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/firmware.h>
15ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/i2c.h>
16ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/leds.h>
17ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/module.h>
18ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/mutex.h>
19c68f46dd6aec29b4db9eb85d014981bbdd686428Sachin Kamat#include <linux/of.h>
20ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/platform_data/leds-lp55xx.h>
21ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include <linux/slab.h>
22ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
23ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#include "leds-lp55xx-common.h"
24ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
25ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_PROGRAM_LENGTH		32
26ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_MAX_LEDS			4
27ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
28ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* ENABLE Register 00h */
29ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_ENABLE		0x00
30ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_EXEC_ENG1_M		0x30
31ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_EXEC_ENG2_M		0x0C
32ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_EXEC_ENG3_M		0x03
33ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_EXEC_M			0x3F
34ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_MASTER_ENABLE		0x40	/* Chip master enable */
35ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_LOGARITHMIC_PWM		0x80	/* Logarithmic PWM adjustment */
36ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_EXEC_RUN			0x2A
37ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENABLE_DEFAULT	\
38ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	(LP5562_MASTER_ENABLE | LP5562_LOGARITHMIC_PWM)
39ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENABLE_RUN_PROGRAM	\
40ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	(LP5562_ENABLE_DEFAULT | LP5562_EXEC_RUN)
41ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
42ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* OPMODE Register 01h */
43ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_OP_MODE		0x01
44ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_MODE_ENG1_M		0x30
45ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_MODE_ENG2_M		0x0C
46ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_MODE_ENG3_M		0x03
47ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_LOAD_ENG1		0x10
48ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_LOAD_ENG2		0x04
49ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_LOAD_ENG3		0x01
50ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_RUN_ENG1			0x20
51ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_RUN_ENG2			0x08
52ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_RUN_ENG3			0x02
53ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG1_IS_LOADING(mode)	\
54ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	((mode & LP5562_MODE_ENG1_M) == LP5562_LOAD_ENG1)
55ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG2_IS_LOADING(mode)	\
56ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	((mode & LP5562_MODE_ENG2_M) == LP5562_LOAD_ENG2)
57ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG3_IS_LOADING(mode)	\
58ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	((mode & LP5562_MODE_ENG3_M) == LP5562_LOAD_ENG3)
59ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
60ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* BRIGHTNESS Registers */
61ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_R_PWM		0x04
62ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_G_PWM		0x03
63ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_B_PWM		0x02
64ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_W_PWM		0x0E
65ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
66ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* CURRENT Registers */
67ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_R_CURRENT		0x07
68ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_G_CURRENT		0x06
69ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_B_CURRENT		0x05
70ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_W_CURRENT		0x0F
71ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
72ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* CONFIG Register 08h */
73ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_CONFIG		0x08
7481f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo#define LP5562_PWM_HF			0x40
7581f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo#define LP5562_PWRSAVE_EN		0x20
7681f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo#define LP5562_CLK_INT			0x01	/* Internal clock */
7781f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo#define LP5562_DEFAULT_CFG		(LP5562_PWM_HF | LP5562_PWRSAVE_EN)
78ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
79ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* RESET Register 0Dh */
80ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_RESET		0x0D
81ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_RESET			0xFF
82ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
83ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* PROGRAM ENGINE Registers */
84ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_PROG_MEM_ENG1	0x10
85ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_PROG_MEM_ENG2	0x30
86ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_PROG_MEM_ENG3	0x50
87ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
88ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* LEDMAP Register 70h */
89ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_REG_ENG_SEL		0x70
90ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG_SEL_PWM		0
91ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG_FOR_RGB_M		0x3F
92ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG_SEL_RGB		0x1B	/* R:ENG1, G:ENG2, B:ENG3 */
93ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG_FOR_W_M		0xC0
94ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG1_FOR_W		0x40	/* W:ENG1 */
95ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG2_FOR_W		0x80	/* W:ENG2 */
96ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_ENG3_FOR_W		0xC0	/* W:ENG3 */
97ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
98ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* Program Commands */
99ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_CMD_DISABLE		0x00
100ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_CMD_LOAD			0x15
101ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_CMD_RUN			0x2A
102ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_CMD_DIRECT		0x3F
103ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo#define LP5562_PATTERN_OFF		0
104ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
105ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic inline void lp5562_wait_opmode_done(void)
106ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
107ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* operation mode change needs to be longer than 153 us */
108ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	usleep_range(200, 300);
109ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
110ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
111ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic inline void lp5562_wait_enable_done(void)
112ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
113ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* it takes more 488 us to update ENABLE register */
114ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	usleep_range(500, 600);
115ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
116ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
117ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_set_led_current(struct lp55xx_led *led, u8 led_current)
118ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
119ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 addr[] = {
120ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_R_CURRENT,
121ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_G_CURRENT,
122ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_B_CURRENT,
123ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_W_CURRENT,
124ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	};
125ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
126ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	led->led_current = led_current;
127ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(led->chip, addr[led->chan_nr], led_current);
128ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
129ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
130ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_load_engine(struct lp55xx_chip *chip)
131ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
132ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	enum lp55xx_engine_index idx = chip->engine_idx;
133ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 mask[] = {
134ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_1] = LP5562_MODE_ENG1_M,
135ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_2] = LP5562_MODE_ENG2_M,
136ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_3] = LP5562_MODE_ENG3_M,
137ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	};
138ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
139ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 val[] = {
140ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_1] = LP5562_LOAD_ENG1,
141ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_2] = LP5562_LOAD_ENG2,
142ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_3] = LP5562_LOAD_ENG3,
143ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	};
144ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
145ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_update_bits(chip, LP5562_REG_OP_MODE, mask[idx], val[idx]);
146ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
147ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_wait_opmode_done();
148ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
149ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
150ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_stop_engine(struct lp55xx_chip *chip)
151ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
152ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DISABLE);
153ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_wait_opmode_done();
154ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
155ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
156ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_run_engine(struct lp55xx_chip *chip, bool start)
157ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
158ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int ret;
159ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 mode;
160ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 exec;
161ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
162ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* stop engine */
163ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (!start) {
164ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp55xx_write(chip, LP5562_REG_ENABLE, LP5562_ENABLE_DEFAULT);
165ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp5562_wait_enable_done();
166ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp5562_stop_engine(chip);
167ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
168ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
169ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp5562_wait_opmode_done();
170ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return;
171ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
172ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
173ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/*
174ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * To run the engine,
175ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * operation mode and enable register should updated at the same time
176ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 */
177ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
178ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp55xx_read(chip, LP5562_REG_OP_MODE, &mode);
179ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
180ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return;
181ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
182ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp55xx_read(chip, LP5562_REG_ENABLE, &exec);
183ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
184ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return;
185ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
186ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* change operation mode to RUN only when each engine is loading */
187ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (LP5562_ENG1_IS_LOADING(mode)) {
188ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		mode = (mode & ~LP5562_MODE_ENG1_M) | LP5562_RUN_ENG1;
189ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		exec = (exec & ~LP5562_EXEC_ENG1_M) | LP5562_RUN_ENG1;
190ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
191ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
192ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (LP5562_ENG2_IS_LOADING(mode)) {
193ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		mode = (mode & ~LP5562_MODE_ENG2_M) | LP5562_RUN_ENG2;
194ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		exec = (exec & ~LP5562_EXEC_ENG2_M) | LP5562_RUN_ENG2;
195ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
196ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
197ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (LP5562_ENG3_IS_LOADING(mode)) {
198ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		mode = (mode & ~LP5562_MODE_ENG3_M) | LP5562_RUN_ENG3;
199ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		exec = (exec & ~LP5562_EXEC_ENG3_M) | LP5562_RUN_ENG3;
200ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
201ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
202ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_OP_MODE, mode);
203ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_wait_opmode_done();
204ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
205ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_update_bits(chip, LP5562_REG_ENABLE, LP5562_EXEC_M, exec);
206ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_wait_enable_done();
207ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
208ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
209ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic int lp5562_update_firmware(struct lp55xx_chip *chip,
210ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo					const u8 *data, size_t size)
211ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
212ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	enum lp55xx_engine_index idx = chip->engine_idx;
213ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 pattern[LP5562_PROGRAM_LENGTH] = {0};
214ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 addr[] = {
215ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_1] = LP5562_REG_PROG_MEM_ENG1,
216ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_2] = LP5562_REG_PROG_MEM_ENG2,
217ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		[LP55XX_ENGINE_3] = LP5562_REG_PROG_MEM_ENG3,
218ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	};
219ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	unsigned cmd;
220ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	char c[3];
221ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int program_size;
222ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int nrchars;
223ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int offset = 0;
224ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int ret;
225ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int i;
226ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
227ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* clear program memory before updating */
228ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	for (i = 0; i < LP5562_PROGRAM_LENGTH; i++)
229ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp55xx_write(chip, addr[idx] + i, 0);
230ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
231ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	i = 0;
232ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	while ((offset < size - 1) && (i < LP5562_PROGRAM_LENGTH)) {
233ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		/* separate sscanfs because length is working only for %s */
234ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
235ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		if (ret != 1)
236ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			goto err;
237ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
238ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		ret = sscanf(c, "%2x", &cmd);
239ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		if (ret != 1)
240ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			goto err;
241ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
242ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		pattern[i] = (u8)cmd;
243ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		offset += nrchars;
244ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		i++;
245ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
246ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
247ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Each instruction is 16bit long. Check that length is even */
248ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (i % 2)
249ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		goto err;
250ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
251ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	program_size = i;
252ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	for (i = 0; i < program_size; i++)
253ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp55xx_write(chip, addr[idx] + i, pattern[i]);
254ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
255ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return 0;
256ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
257ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Miloerr:
258ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	dev_err(&chip->cl->dev, "wrong pattern format\n");
259ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return -EINVAL;
260ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
261ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
262ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_firmware_loaded(struct lp55xx_chip *chip)
263ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
264ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	const struct firmware *fw = chip->fw;
265ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
266ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (fw->size > LP5562_PROGRAM_LENGTH) {
267ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
268ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			fw->size);
269ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return;
270ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
271ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
272ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/*
273ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * Program momery sequence
274ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 *  1) set engine mode to "LOAD"
275ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 *  2) write firmware data into program memory
276ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 */
277ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
278ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_load_engine(chip);
279ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_update_firmware(chip, fw->data, fw->size);
280ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
281ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
282ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic int lp5562_post_init_device(struct lp55xx_chip *chip)
283ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
284ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int ret;
28581f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo	u8 cfg = LP5562_DEFAULT_CFG;
286ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
287ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Set all PWMs to direct control mode */
288ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
289ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
290ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return ret;
291ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
292ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_wait_opmode_done();
293ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
29481f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo	/* Update configuration for the clock setting */
29581f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo	if (!lp55xx_is_extclk_used(chip))
29681f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo		cfg |= LP5562_CLK_INT;
29781f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo
29881f2a5b4a0570a662efd629c176fc1d67e56f7e3Kim, Milo	ret = lp55xx_write(chip, LP5562_REG_CONFIG, cfg);
299ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
300ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return ret;
301ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
302ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Initialize all channels PWM to zero -> leds off */
303ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_R_PWM, 0);
304ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_G_PWM, 0);
305ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_B_PWM, 0);
306ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_W_PWM, 0);
307ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
308ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Set LED map as register PWM by default */
309ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
310ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
311ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return 0;
312ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
313ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
314ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_led_brightness_work(struct work_struct *work)
315ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
316ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_led *led = container_of(work, struct lp55xx_led,
317ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo					      brightness_work);
318ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_chip *chip = led->chip;
319ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 addr[] = {
320ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_R_PWM,
321ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_G_PWM,
322ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_B_PWM,
323ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		LP5562_REG_W_PWM,
324ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	};
325ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
326ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_lock(&chip->lock);
327ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, addr[led->chan_nr], led->brightness);
328ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_unlock(&chip->lock);
329ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
330ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
331ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic void lp5562_write_program_memory(struct lp55xx_chip *chip,
332ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo					u8 base, const u8 *rgb, int size)
333ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
334ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int i;
335ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
336ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (!rgb || size <= 0)
337ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return;
338ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
339ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	for (i = 0; i < size; i++)
340ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp55xx_write(chip, base + i, *(rgb + i));
341ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
342ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, base + i, 0);
343ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, base + i + 1, 0);
344ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
345ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
346ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* check the size of program count */
347ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn)
348ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
349432eb69dd845d239213e714ae2b9efec3dcdf230Jingoo Han	return ptn->size_r >= LP5562_PROGRAM_LENGTH ||
350432eb69dd845d239213e714ae2b9efec3dcdf230Jingoo Han	       ptn->size_g >= LP5562_PROGRAM_LENGTH ||
351432eb69dd845d239213e714ae2b9efec3dcdf230Jingoo Han	       ptn->size_b >= LP5562_PROGRAM_LENGTH;
352ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
353ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
354ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode)
355ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
356ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_predef_pattern *ptn;
357ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int i;
358ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
359ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (mode == LP5562_PATTERN_OFF) {
360ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp5562_run_engine(chip, false);
361ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return 0;
362ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
363ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
364ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ptn = chip->pdata->patterns + (mode - 1);
365ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (!ptn || _is_pc_overflow(ptn)) {
366ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		dev_err(&chip->cl->dev, "invalid pattern data\n");
367ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return -EINVAL;
368ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
369ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
370ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_stop_engine(chip);
371ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
372ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Set LED map as RGB */
373ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_RGB);
374ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
375ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Load engines */
376ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	for (i = LP55XX_ENGINE_1; i <= LP55XX_ENGINE_3; i++) {
377ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		chip->engine_idx = i;
378ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		lp5562_load_engine(chip);
379ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
380ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
381ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Clear program registers */
382ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG1, 0);
383ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG1 + 1, 0);
384ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG2, 0);
385ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG2 + 1, 0);
386ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG3, 0);
387ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG3 + 1, 0);
388ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
389ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Program engines */
390ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG1,
391ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				ptn->r, ptn->size_r);
392ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG2,
393ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				ptn->g, ptn->size_g);
394ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG3,
395ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				ptn->b, ptn->size_b);
396ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
397ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* Run engines */
398ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_run_engine(chip, true);
399ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
400ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return 0;
401ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
402ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
403ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic ssize_t lp5562_store_pattern(struct device *dev,
404ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				struct device_attribute *attr,
405ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				const char *buf, size_t len)
406ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
407ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
408ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_chip *chip = led->chip;
409ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_predef_pattern *ptn = chip->pdata->patterns;
410ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int num_patterns = chip->pdata->num_patterns;
411ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	unsigned long mode;
412ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int ret;
413ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
414ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = kstrtoul(buf, 0, &mode);
415ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
416ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return ret;
417ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
418ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (mode > num_patterns || !ptn)
419ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return -EINVAL;
420ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
421ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_lock(&chip->lock);
422ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp5562_run_predef_led_pattern(chip, mode);
423ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_unlock(&chip->lock);
424ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
425ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
426ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return ret;
427ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
428ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return len;
429ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
430ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
431ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic ssize_t lp5562_store_engine_mux(struct device *dev,
432ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				     struct device_attribute *attr,
433ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo				     const char *buf, size_t len)
434ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
435ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
436ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_chip *chip = led->chip;
437ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 mask;
438ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	u8 val;
439ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
440ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	/* LED map
441ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * R ... Engine 1 (fixed)
442ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * G ... Engine 2 (fixed)
443ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * B ... Engine 3 (fixed)
444ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 * W ... Engine 1 or 2 or 3
445ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	 */
446ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
447ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (sysfs_streq(buf, "RGB")) {
448ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		mask = LP5562_ENG_FOR_RGB_M;
449ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		val = LP5562_ENG_SEL_RGB;
450ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	} else if (sysfs_streq(buf, "W")) {
451ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		enum lp55xx_engine_index idx = chip->engine_idx;
452ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
453ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		mask = LP5562_ENG_FOR_W_M;
454ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		switch (idx) {
455ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		case LP55XX_ENGINE_1:
456ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			val = LP5562_ENG1_FOR_W;
457ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			break;
458ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		case LP55XX_ENGINE_2:
459ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			val = LP5562_ENG2_FOR_W;
460ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			break;
461ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		case LP55XX_ENGINE_3:
462ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			val = LP5562_ENG3_FOR_W;
463ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			break;
464ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		default:
465ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			return -EINVAL;
466ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		}
467ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
468ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	} else {
469ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		dev_err(dev, "choose RGB or W\n");
470ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return -EINVAL;
471ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
472ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
473ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_lock(&chip->lock);
474ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_update_bits(chip, LP5562_REG_ENG_SEL, mask, val);
475ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_unlock(&chip->lock);
476ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
477ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return len;
478ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
479ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
480daa124b1fe992f27f96d89cde5923bb929e28c1cMilo Kimstatic LP55XX_DEV_ATTR_WO(led_pattern, lp5562_store_pattern);
481daa124b1fe992f27f96d89cde5923bb929e28c1cMilo Kimstatic LP55XX_DEV_ATTR_WO(engine_mux, lp5562_store_engine_mux);
482ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
483ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic struct attribute *lp5562_attributes[] = {
484ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	&dev_attr_led_pattern.attr,
485ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	&dev_attr_engine_mux.attr,
486ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	NULL,
487ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo};
488ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
489ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic const struct attribute_group lp5562_group = {
490ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.attrs = lp5562_attributes,
491ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo};
492ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
493ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo/* Chip specific configurations */
494ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic struct lp55xx_device_config lp5562_cfg = {
495ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.max_channel  = LP5562_MAX_LEDS,
496ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.reset = {
497ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		.addr = LP5562_REG_RESET,
498ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		.val  = LP5562_RESET,
499ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	},
500ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.enable = {
501ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		.addr = LP5562_REG_ENABLE,
502ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		.val  = LP5562_ENABLE_DEFAULT,
503ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	},
504ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.post_init_device   = lp5562_post_init_device,
505ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.set_led_current    = lp5562_set_led_current,
506ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.brightness_work_fn = lp5562_led_brightness_work,
507ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.run_engine         = lp5562_run_engine,
508ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.firmware_cb        = lp5562_firmware_loaded,
509ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.dev_attr_group     = &lp5562_group,
510ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo};
511ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
512ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic int lp5562_probe(struct i2c_client *client,
513ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			const struct i2c_device_id *id)
514ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
515ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	int ret;
516ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_chip *chip;
517ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_led *led;
518e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo	struct lp55xx_platform_data *pdata;
519e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo	struct device_node *np = client->dev.of_node;
520e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo
52187aae1ea82f93f0f00cb955044ea1db3501cf233Jingoo Han	if (!dev_get_platdata(&client->dev)) {
522e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo		if (np) {
523e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo			ret = lp55xx_of_populate_pdata(&client->dev, np);
524e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo			if (ret < 0)
525e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo				return ret;
526e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo		} else {
527e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo			dev_err(&client->dev, "no platform data\n");
528e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo			return -EINVAL;
529e015050cc5ea01e4beba3862dcafef9360c77522Kim, Milo		}
530ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
53187aae1ea82f93f0f00cb955044ea1db3501cf233Jingoo Han	pdata = dev_get_platdata(&client->dev);
532ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
533ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
534ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (!chip)
535ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return -ENOMEM;
536ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
537ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	led = devm_kzalloc(&client->dev,
538ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo			sizeof(*led) * pdata->num_channels, GFP_KERNEL);
539ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (!led)
540ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		return -ENOMEM;
541ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
542ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	chip->cl = client;
543ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	chip->pdata = pdata;
544ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	chip->cfg = &lp5562_cfg;
545ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
546ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	mutex_init(&chip->lock);
547ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
548ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	i2c_set_clientdata(client, led);
549ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
550ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp55xx_init_device(chip);
551ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
552ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		goto err_init;
553ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
554ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp55xx_register_leds(led, chip);
555ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret)
556ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		goto err_register_leds;
557ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
558ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	ret = lp55xx_register_sysfs(chip);
559ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	if (ret) {
560ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		dev_err(&client->dev, "registering sysfs failed\n");
561ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		goto err_register_sysfs;
562ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	}
563ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
564ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return 0;
565ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
566ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Miloerr_register_sysfs:
567ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_unregister_leds(led, chip);
568ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Miloerr_register_leds:
569ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_deinit_device(chip);
570ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Miloerr_init:
571ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return ret;
572ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
573ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
574ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic int lp5562_remove(struct i2c_client *client)
575ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo{
576ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_led *led = i2c_get_clientdata(client);
577ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	struct lp55xx_chip *chip = led->chip;
578ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
579ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp5562_stop_engine(chip);
580ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
581ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_unregister_sysfs(chip);
582ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_unregister_leds(led, chip);
583ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	lp55xx_deinit_device(chip);
584ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
585ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	return 0;
586ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo}
587ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
588ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic const struct i2c_device_id lp5562_id[] = {
589ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	{ "lp5562", 0 },
590ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	{ }
591ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo};
592ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, MiloMODULE_DEVICE_TABLE(i2c, lp5562_id);
593ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
59428720cff9feeb705a39f54c196bc529fb33d1542Axel Lin#ifdef CONFIG_OF
59528720cff9feeb705a39f54c196bc529fb33d1542Axel Linstatic const struct of_device_id of_lp5562_leds_match[] = {
59628720cff9feeb705a39f54c196bc529fb33d1542Axel Lin	{ .compatible = "ti,lp5562", },
59728720cff9feeb705a39f54c196bc529fb33d1542Axel Lin	{},
59828720cff9feeb705a39f54c196bc529fb33d1542Axel Lin};
59928720cff9feeb705a39f54c196bc529fb33d1542Axel Lin
60028720cff9feeb705a39f54c196bc529fb33d1542Axel LinMODULE_DEVICE_TABLE(of, of_lp5562_leds_match);
60128720cff9feeb705a39f54c196bc529fb33d1542Axel Lin#endif
60228720cff9feeb705a39f54c196bc529fb33d1542Axel Lin
603ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milostatic struct i2c_driver lp5562_driver = {
604ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.driver = {
605ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo		.name	= "lp5562",
60628720cff9feeb705a39f54c196bc529fb33d1542Axel Lin		.of_match_table = of_match_ptr(of_lp5562_leds_match),
607ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	},
608ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.probe		= lp5562_probe,
609ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.remove		= lp5562_remove,
610ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo	.id_table	= lp5562_id,
611ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo};
612ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
613ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milomodule_i2c_driver(lp5562_driver);
614ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, Milo
615ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, MiloMODULE_DESCRIPTION("Texas Instruments LP5562 LED Driver");
616ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, MiloMODULE_AUTHOR("Milo Kim");
617ff45262a85dbf1bc74463c5dcea1d71a406d4d8eKim, MiloMODULE_LICENSE("GPL");
618