| #include <linux/ctype.h> |
| #include <amlogic/leds-lp50xx.h> |
| #include <amlogic/leds-main.h> |
| |
| static struct udevice *g_led_devp; |
| static enum LP50XX_INIT_STATUS led_init_ready; |
| |
| #define CAL_FILE_LEN 2048 |
| |
| static int get_n_dot_data(const char *buffer, |
| const char *start_label, const char *end_label, char *data, size_t data_size) |
| { |
| const char *start = strstr(buffer, start_label); |
| const char *end = strstr(start, end_label); |
| int length; |
| |
| if (!start || !end) { |
| pr_err("LED: cannot found n_dot data\n"); |
| return -1; |
| } |
| |
| length = end - start; |
| if (length >= data_size) |
| length = data_size - 1; |
| |
| memcpy(data, start, length); |
| data[length] = '\0'; |
| |
| return 0; |
| } |
| |
| static void parse_and_convert(const char *p, unsigned long settings_[], int len) |
| { |
| const char *ptr = p; |
| char num_str[16]; |
| int i = 0; |
| int j = 0; |
| |
| while (*ptr != '\0' && i < N_CAL_SETTINGS) { |
| memset(num_str, 0, sizeof(num_str)); |
| j = 0; |
| |
| while (*ptr != ',' && *ptr != ';' && *ptr != '\0') |
| num_str[j++] = *ptr++; |
| |
| settings_[i++] = simple_strtoul(num_str, NULL, 10); |
| |
| if (*ptr == ',' || *ptr == ';') |
| ptr++; |
| } |
| } |
| |
| void lp50xx_get_cal_settings(unsigned int *settings, const char color_header[], |
| unsigned int led_index) |
| { |
| int i; |
| unsigned long settings_[N_CAL_SETTINGS]; |
| const char *p; |
| char rgbw_buf[CAL_FILE_LEN]; |
| char start_label[8]; |
| char end_label[8]; |
| |
| const unsigned int max_chars = CAL_FILE_LEN; |
| char buf[max_chars]; |
| |
| if (get_cal_string(buf, max_chars)) |
| return; |
| |
| snprintf(start_label, sizeof(start_label), "%s%d", "n_dot_", led_index); |
| if (led_index < LP50XX_NUM_LEDS - 1) |
| snprintf(end_label, sizeof(end_label), "%s%d", "n_dot_", led_index + 1); |
| else |
| snprintf(end_label, sizeof(end_label), "%s%d", "status_", 0); |
| |
| if (get_n_dot_data(buf, start_label, end_label, rgbw_buf, sizeof(rgbw_buf))) |
| return; |
| |
| p = strstr(rgbw_buf, color_header); |
| if (!p) { |
| pr_err("LED: \"%s\" not found in cal file segment: %s\n", |
| color_header, buf); |
| return; |
| } |
| p += strlen(color_header); |
| parse_and_convert(p, settings_, sizeof(p)); |
| |
| for (i = 0; i < N_CAL_SETTINGS; ++i) |
| settings[i] = (unsigned int)settings_[i]; |
| } |
| |
| static void lp50xx_led_write_byte(struct udevice *led_devp, uint reg, int val) |
| { |
| dm_i2c_reg_write(led_devp, reg, val); |
| } |
| |
| static void led_turn_off_write(struct udevice *led_devp, unsigned int led_index) |
| { |
| int i; |
| |
| for (i = 0; i < 3; ++i) |
| lp50xx_led_write_byte(led_devp, LP50XX_COLOR_BASE + led_index * 3 + i, 0); |
| lp50xx_led_write_byte(led_devp, LP50XX_BRIGHTNESS_BASE + led_index, 0xff); |
| } |
| |
| static void led_cal_setting_write(unsigned int *cal_settings, |
| struct udevice *led_devp, unsigned int led_index) |
| { |
| u8 brightness; |
| int i; |
| u8 rgb[3] = {0}; |
| |
| // color |
| for (i = 0; i < 3; ++i) { |
| rgb[i] = cal_settings[i]; |
| lp50xx_led_write_byte(led_devp, LP50XX_COLOR_BASE + led_index * 3 + i, rgb[i]); |
| } |
| |
| // brightness |
| brightness = cal_settings[3]; |
| lp50xx_led_write_byte(led_devp, LP50XX_BRIGHTNESS_BASE + led_index, brightness); |
| } |
| |
| static void turn_on_white_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "White:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void turn_on_yellow_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "NestYellow:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void turn_on_green_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "NestGreen:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void turn_on_blue_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "NestBlue:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void turn_on_orange_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "NestOrange:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void turn_on_purple_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "NestPurple:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void turn_on_pink_led(struct udevice *led_devp, unsigned int led_index) |
| { |
| unsigned int cal_settings[N_CAL_SETTINGS] = {0, 0, 0, 0}; |
| char color_header[] = "NestPink:"; |
| |
| lp50xx_get_cal_settings(cal_settings, color_header, led_index); |
| pr_info("LED: index(%d) show %s%d,%d,%d;%d\n", led_index, color_header, |
| cal_settings[0], cal_settings[1], cal_settings[2], cal_settings[3]); |
| led_cal_setting_write(cal_settings, led_devp, led_index); |
| } |
| |
| static void lp50xx_set_banks(struct udevice *led_devp) |
| { |
| int val = dm_i2c_reg_read(led_devp, LP50XX_DEVICE_CONFIG1); |
| |
| if (!(val & LP50XX_Auto_Incr_EN)) { |
| val |= LP50XX_Auto_Incr_EN; |
| lp50xx_led_write_byte(led_devp, LP50XX_DEVICE_CONFIG1, val); |
| } |
| } |
| |
| int lp50xx_sys_led_init(void) |
| { |
| int ret = 0; |
| struct udevice *led_devp = NULL; |
| int i; |
| |
| if (led_init_ready) |
| return ret; |
| |
| led_init_ready = INIT_DONE; |
| |
| ret = i2c_get_chip_for_busnum(LP50XX_I2C_BUS_NUM, LP50XX_I2C_LED_REG, 1, &led_devp); |
| if (ret) { |
| pr_info("LED: i2c can't get bus 0x%x\n", LP50XX_I2C_LED_REG); |
| led_init_ready = INIT_NO_USED; |
| return ret; |
| } |
| |
| // Enable driver |
| // Set Chip_EN |
| lp50xx_led_write_byte(led_devp, LP50XX_DEVICE_CONFIG0, 0x40); |
| // Set Log_Scale_EN = 0, Power_save_EN = 1, Auto_incr_EN = 1 and |
| // PWM_Dithering_EN = 1 |
| lp50xx_led_write_byte(led_devp, LP50XX_DEVICE_CONFIG1, 0x1C); |
| // Set default brightness to 0xFF |
| for (i = 0; i < LP50XX_NUM_LEDS; ++i) |
| lp50xx_led_write_byte(led_devp, LP50XX_BRIGHTNESS_BASE + i, 0xFF); |
| |
| lp50xx_set_banks(led_devp); |
| |
| g_led_devp = led_devp; |
| return ret; |
| } |
| |
| int lp50xx_turn_on_led(enum LED_ANIMATION led_animation, unsigned int led_index) |
| { |
| int ret; |
| struct udevice *led_devp; |
| |
| if (check_read_cal_done() == -1) |
| return -1; |
| |
| if (led_init_ready == INIT_NO_USED) |
| return -1; |
| |
| if (led_init_ready != INIT_DONE) { |
| ret = lp50xx_sys_led_init(); |
| if (ret) |
| return ret; |
| } |
| |
| if (led_index >= LP50XX_NUM_LEDS) { |
| pr_err("LED: %s Can't to find led_index: %d\n", |
| __func__, led_index); |
| return -1; |
| } |
| |
| led_devp = g_led_devp; |
| |
| switch(led_animation) { |
| case WHITE: |
| turn_on_white_led(led_devp, led_index); |
| break; |
| case YELLOW: |
| turn_on_yellow_led(led_devp, led_index); |
| break; |
| case GREEN: |
| turn_on_green_led(led_devp, led_index); |
| break; |
| case BLUE: |
| turn_on_blue_led(led_devp, led_index); |
| break; |
| case ORANGE: |
| turn_on_orange_led(led_devp, led_index); |
| break; |
| case PURPLE: |
| turn_on_purple_led(led_devp, led_index); |
| break; |
| case PINK: |
| turn_on_pink_led(led_devp, led_index); |
| break; |
| default: |
| pr_err("LED: %s unknown led animation\n", __func__); |
| } |
| |
| return 0; |
| } |
| |
| int lp50xx_turn_off_led(unsigned int led_index) |
| { |
| int ret; |
| struct udevice *led_devp; |
| |
| if (led_init_ready == INIT_NO_USED) |
| return -1; |
| |
| if (led_init_ready != INIT_DONE) { |
| ret = lp50xx_sys_led_init(); |
| if (ret) |
| return ret; |
| } |
| |
| if (led_index >= LP50XX_NUM_LEDS) { |
| pr_err("LED: %s Can't to find led_index: %d\n", |
| __func__, led_index); |
| return -1; |
| } |
| |
| led_devp = g_led_devp; |
| |
| led_turn_off_write(led_devp, led_index); |
| return 0; |
| } |
| |
| void lp50xx_uboot_init_led_status(void) |
| { |
| int i; |
| |
| for (i = 0; i < LP50XX_NUM_LEDS; ++i) |
| lp50xx_turn_off_led(i); |
| |
| // show group index is 2/3/6/7 led |
| const int indexs[] = {2, 3, 6, 7}; |
| int length = sizeof(indexs) / sizeof(indexs[0]); |
| |
| for (i = 0; i < length; ++i) |
| lp50xx_turn_on_led(WHITE, indexs[i]); |
| } |
| |
| void lp50xx_start_kernel_led_status(void) |
| { |
| int i; |
| |
| for (i = 0; i < LP50XX_NUM_LEDS; ++i) |
| lp50xx_turn_off_led(i); |
| |
| // show all leds |
| for (i = 0; i < LP50XX_NUM_LEDS; ++i) |
| lp50xx_turn_on_led(WHITE, i); |
| } |
| |
| void lp50xx_udisk_update_led_status(void) |
| { |
| int i; |
| |
| // show 0/1/7 green led |
| for (i = 0; i < LP50XX_NUM_LEDS; ++i) { |
| if (i == 0 || i == 1 || i == 7) |
| lp50xx_turn_on_led(GREEN, i); |
| else |
| lp50xx_turn_off_led(i); |
| } |
| } |