blob: c92cb8bcdf892f10384c3a87b74650004eb6496d [file] [log] [blame]
#include "util.h"
#include "i2c_driver.h"
#define AW21018_REG_GCR 0x20
#define AW21018_REG_BRIGHTNESS_BASE 0x21
#define AW21018_REG_UPDATE 0x45
#define AW21018_REG_SL_BASE 0x46
#define AW21018_REG_GCCR 0x58
#define AW21018_REG_GCR2 0x61
#define AW21018_REG_DEVICE_RESET 0x70
#define AW21018_CHIPID 0x02
#define AW21018_REG_GCR_CHIPEN_BIT (1 << 0)
#define AW21018_REG_GCR_AUTO_POWER_BIT (1 << 7)
#define AW21018_REG_GCR2_RGBMD_BIT (1 << 0)
#define AW21018_REG_GCR2_SBMD_BIT (1 << 1)
/* Global Current is read from the DTS entry by the kernel driver.
* Here in the bootloader we will just hardcode it. */
#define AW21018_GLOBAL_CURRENT 0x66
#define AW21018_MAX_LED_CHANNELS 18
#define AW21018_MAX_LED_GROUPS 6
extern int lgpl_printf(const char *format, ...);
extern int i2c_master_write_and_read(int id, int target_addr, unsigned char* send_buff, int send_len, unsigned char* recv_buff, int recv_len);
int diag_i2c_led_aw210xx_detect_driver(int master_id, unsigned char slave_addr) {
unsigned char tx_buf = AW21018_REG_DEVICE_RESET;
unsigned char rx_buf = 0xFF;
int ret;
lgpl_printf("%s: master_id: %d slave_addr: 0x%x\n", __func__, master_id, slave_addr);
ret = i2c_master_write_and_read(master_id, slave_addr, &tx_buf, 1, &rx_buf, 1);
if (ret != 0) {
lgpl_printf("%s: failed to read reset register.\n", __func__);
return ret;
}
if (AW21018_CHIPID != rx_buf) {
lgpl_printf("%s: chip ID did not match expected value: %d (expected: %d).\n", __func__,
rx_buf, AW21018_CHIPID);
return -1;
}
return 0;
}
static void aw210xx_write_register(int master_id, unsigned char slave_addr,
unsigned char reg, unsigned char val)
{
unsigned char tx_buf[2];
int ret;
tx_buf[0] = reg;
tx_buf[1] = val;
ret = i2c_master_write_and_read(master_id, slave_addr, tx_buf, 2, 0, 0);
if (ret != 0) {
lgpl_printf("%s: failed to set register 0x%x: error = 0x%x.\n", __func__, reg, ret);
}
}
static void aw210xx_set_update_register(int master_id, unsigned char slave_addr) {
aw210xx_write_register(master_id, slave_addr, AW21018_REG_UPDATE, 0x00);
}
static void aw210xx_set_brightness_registers(int master_id,
unsigned char slave_addr, unsigned char *reg_data, size_t size)
{
unsigned char tx_buf[AW21018_MAX_LED_GROUPS + 1];
int len = 1;
size_t i;
int ret;
/* The bootloader only operates the driver in Single Byte Configuration mode.
* Only allow setting the first 6 BR registers */
tx_buf[0] = AW21018_REG_BRIGHTNESS_BASE;
for (i = 1; i < AW21018_MAX_LED_GROUPS + 1; i++) {
if (i <= size) {
tx_buf[i] = reg_data[i - 1];
len++;
} else {
tx_buf[i] = 0;
}
}
ret = i2c_master_write_and_read(master_id, slave_addr, tx_buf, len, 0, 0);
if (ret != 0) {
lgpl_printf("%s: failed to set brightness registers: error = 0x%x.\n", __func__, ret);
}
aw210xx_set_update_register(master_id, slave_addr);
}
static void aw210xx_set_sl_registers(int master_id,
unsigned char slave_addr, unsigned char *reg_data, size_t size)
{
unsigned char tx_buf[AW21018_MAX_LED_CHANNELS + 1];
int len = 1;
size_t i;
int ret;
tx_buf[0] = AW21018_REG_SL_BASE;
for (i = 1; i < AW21018_MAX_LED_CHANNELS + 1; i++) {
if (i <= size) {
tx_buf[i] = reg_data[i - 1];
len++;
} else {
tx_buf[i] = 0;
}
}
ret = i2c_master_write_and_read(master_id, slave_addr, tx_buf, len, 0, 0);
if (ret != 0) {
lgpl_printf("%s: failed to set SL registers: error = 0x%x.\n", __func__, ret);
}
aw210xx_set_update_register(master_id, slave_addr);
}
int diag_i2c_led_aw210xx_init(int master_id, unsigned char slave_addr) {
lgpl_printf("%s: master_id: %d slave_addr: 0x%x\n", __func__, master_id, slave_addr);
// Set CHIPEN to put AS21018 into active mode
aw210xx_write_register(master_id, slave_addr, AW21018_REG_GCR, AW21018_REG_GCR_CHIPEN_BIT);
// Set RGB Mode and Single Byte Configuration mode
aw210xx_write_register(master_id, slave_addr, AW21018_REG_GCR2,
(AW21018_REG_GCR2_RGBMD_BIT | AW21018_REG_GCR2_SBMD_BIT));
// Set the global current control register to predefined value
aw210xx_write_register(master_id, slave_addr, AW21018_REG_GCCR, AW21018_GLOBAL_CURRENT);
// Set Auto power saving mode
aw210xx_write_register(master_id, slave_addr, AW21018_REG_GCR,
(AW21018_REG_GCR_AUTO_POWER_BIT | AW21018_REG_GCR_CHIPEN_BIT));
return 0;
}
int diag_i2c_led_aw210xx_set_frame(int master_id, unsigned char slave_addr,
unsigned char *frame, size_t size)
{
unsigned char br_buf[AW21018_MAX_LED_GROUPS] = {0};
unsigned char sl_buf[AW21018_MAX_LED_CHANNELS] = {0};
size_t br_index = 0;
size_t sl_index = 0;
size_t i = 0;
lgpl_printf("%s: master_id: %d slave_addr: 0x%x frame: 0x%x size: %d\n", __func__,
master_id, slave_addr, frame, size);
// The frame should contain at least 8 bytes for brightness
if (size < 8) {
return -1;
}
/* First 8 bytes of the frame represent the brightness of 8 LEDs
* AW21018 only supports 6 LED BR registers in RGBMD so we only copy
* the first 6 values from the frame */
for (i = 0; i < AW21018_MAX_LED_GROUPS; i++) {
br_buf[br_index++] = frame[i];
}
/* Remaining 24 bytes of the frame represent RGB values.
* AW21018 only supports 18 channels so we only copy the first 18
* bytes of data */
for (i = 8; ((i < size) && (sl_index < AW21018_MAX_LED_CHANNELS)); i+=3) {
sl_buf[sl_index++] = frame[i];
sl_buf[sl_index++] = frame[i + 1];
sl_buf[sl_index++] = frame[i + 2];
}
aw210xx_set_brightness_registers(master_id, slave_addr, br_buf, br_index);
aw210xx_set_sl_registers(master_id, slave_addr, sl_buf, sl_index);
return 0;
}