summaryrefslogtreecommitdiff
path: root/driver/led/tlc59116f.c
blob: b1c16a921bd852fc6ca351b80634dc1c90478b3c (plain)
1
2
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* Copyright 2022 The ChromiumOS Authors.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include <string.h>

#include "common.h"
#include "console.h"
#include "i2c.h"
#include "rgb_keyboard.h"
#include "stddef.h"
#include "tlc59116f.h"

#define CPRINTF(fmt, args...) cprintf(CC_RGBKBD, "TLC59116F: " fmt, ##args)
#define CPRINTS(fmt, args...) cprints(CC_RGBKBD, "TLC59116F: " fmt, ##args)

#define TLC59116F_BUF_SIZE	(SIZE_OF_RGB * TLC59116F_GRID_SIZE)
#define TLC59116_MODE_BIT_SLEEP		4

static int tlc59116f_read(struct rgbkbd *ctx, uint8_t addr, uint8_t *value)
{
	return i2c_xfer(ctx->cfg->i2c, TLC59116F_I2C_ADDR_FLAG,
			&addr, sizeof(addr), value, sizeof(*value));
}

static int tlc59116f_write(struct rgbkbd *ctx, uint8_t addr, uint8_t value)
{
	uint8_t buf[2] = {
		[0] = addr,
		[1] = value,
	};

	return i2c_xfer(ctx->cfg->i2c, TLC59116F_I2C_ADDR_FLAG,
			buf, sizeof(buf), NULL, 0);
}

static int tlc59116f_reset(struct rgbkbd *ctx)
{
	return i2c_write8(ctx->cfg->i2c, TLC59116F_RESET, 0xA5, 0x5A);
}

static int tlc59116f_init(struct rgbkbd *ctx)
{
	int i, rv;

	for (i = TLC59116F_LEDOUT0; i <= TLC59116F_LEDOUT3; i++) {
		rv = tlc59116f_write(ctx, i, TLC59116_LEDOUT_PWM);
		if (rv) {
			return rv;
		}
	}

	rv = tlc59116f_write(ctx, TLC59116F_MODE1, 0x01);
	if (rv) {
		CPRINTS("Failed to set TLC59116F normal mode");
		return rv;
	}

	return EC_SUCCESS;
}

static int tlc59116f_enable(struct rgbkbd *ctx, bool enable)
{
	uint8_t cfg;
	int rv;

	rv = tlc59116f_read(ctx, TLC59116F_MODE1, &cfg);
	if (rv) {
		CPRINTS("Failed to enable TLC59116F");
		return rv;
	}

	WRITE_BIT(cfg, TLC59116_MODE_BIT_SLEEP, !enable);
	return tlc59116f_write(ctx, TLC59116F_MODE1, cfg);
}

static int tlc59116f_set_color(struct rgbkbd *ctx, uint8_t offset,
				struct rgb_s *color, uint8_t len)
{
	uint8_t buf[sizeof(offset) + TLC59116F_BUF_SIZE];
	const int frame_len = len * SIZE_OF_RGB + sizeof(offset);
	const int frame_offset = offset * SIZE_OF_RGB;
	int i;

	if (frame_offset + frame_len > sizeof(buf)) {
		return EC_ERROR_OVERFLOW;
	}

	buf[0] = TLC59116_AI_BRIGHTNESS_ONLY |
			(frame_offset + TLC59116F_PWM0);
	for (i = 0; i < len; i++) {
		buf[i * SIZE_OF_RGB + 1] = color[i].r;
		buf[i * SIZE_OF_RGB + 2] = color[i].g;
		buf[i * SIZE_OF_RGB + 3] = color[i].b;
	}

	return i2c_xfer(ctx->cfg->i2c, TLC59116F_I2C_ADDR_FLAG,
			buf, frame_len, NULL, 0);
}

static int tlc59116f_set_scale(struct rgbkbd *ctx, uint8_t offset,
				 struct rgb_s scale, uint8_t len)
{
	/* tlc59116f not support scale function */
	return EC_SUCCESS;
}

static int tlc59116f_set_gcc(struct rgbkbd *ctx, uint8_t level)
{
	int j, rv;

	for (j = TLC59116F_LEDOUT0; j <= TLC59116F_LEDOUT3; j++) {
		rv = tlc59116f_write(ctx, j, TLC59116_LEDOUT_GROUP);
		if (rv) {
			return rv;
		}
	}

	return tlc59116f_write(ctx, TLC59116F_GRPPWM, level);
}

const struct rgbkbd_drv tlc59116f_drv = {
	.reset = tlc59116f_reset,
	.init = tlc59116f_init,
	.enable = tlc59116f_enable,
	.set_color = tlc59116f_set_color,
	.set_scale = tlc59116f_set_scale,
	.set_gcc = tlc59116f_set_gcc,
};