| /* |
| * drivers/amlogic/media/vout/lcd/bl_ldim/iw7019.c |
| * |
| * Copyright (C) 2015 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include <common.h> |
| #include <malloc.h> |
| #include <spi.h> |
| #include <asm/arch/gpio.h> |
| #include <fdtdec.h> |
| #include <amlogic/media/vout/lcd/aml_lcd.h> |
| #include <amlogic/media/vout/lcd/bl_ldim.h> |
| #include "../lcd_reg.h" |
| #include "../lcd_common.h" |
| #include "ldim_drv.h" |
| #include "ldim_dev_drv.h" |
| |
| static struct ldim_dev_config_s *ldim_dev_config; |
| static int ldim_dev_probe_flag; |
| |
| struct ldim_spi_dev_info_s ldim_spi_info = { |
| .modalias = "ldim_dev", |
| .spi_name = "none", |
| .mode = SPI_MODE_0, |
| .max_speed_hz = 1000000, /* 1MHz */ |
| .bus_num = 0, /* SPI bus No. */ |
| .chip_select = 0, /* the device index on the spi bus */ |
| .wordlen = 8, |
| .spi = NULL, |
| }; |
| |
| /* *************************************** |
| * ldim gpio |
| * *************************************** */ |
| static struct lcd_cpu_gpio_s ldim_gpio[BL_GPIO_NUM_MAX] = { |
| {.name = "invalid", .probe_flag = 0, .register_flag = 0,}, |
| {.name = "invalid", .probe_flag = 0, .register_flag = 0,}, |
| {.name = "invalid", .probe_flag = 0, .register_flag = 0,}, |
| {.name = "invalid", .probe_flag = 0, .register_flag = 0,}, |
| {.name = "invalid", .probe_flag = 0, .register_flag = 0,}, |
| }; |
| |
| static int ldim_gpio_probe(const char *name, int index) |
| { |
| if (name == NULL) { |
| LDIMERR("bl: %s: gpio name is null\n", __func__); |
| return -1; |
| } |
| if (index >= BL_GPIO_NUM_MAX) { |
| LDIMERR("bl: %s: invalid gpio: %d\n", __func__, index); |
| return -1; |
| } |
| if (ldim_gpio[index].probe_flag == 1) { |
| if (lcd_debug_print_flag) { |
| LDIMPR("bl: gpio %s(%d) is already probed\n", |
| ldim_gpio[index].name, index); |
| } |
| return 0; |
| } |
| |
| if (lcd_debug_print_flag) |
| LDIMPR("bl: probe gpio: %s(%d)\n", name, index); |
| strcpy(ldim_gpio[index].name, name); |
| /* init gpio flag */ |
| ldim_gpio[index].probe_flag = 1; |
| ldim_gpio[index].register_flag = 0; |
| |
| return 0; |
| } |
| |
| static int ldim_gpio_request(int index) |
| { |
| int ret = 0; |
| |
| if (index >= BL_GPIO_NUM_MAX) { |
| LDIMERR("bl: %s: invalid gpio: %d\n", __func__, index); |
| return -1; |
| } |
| if (ldim_gpio[index].probe_flag == 0) { |
| LDIMERR("bl: gpio %d is not probed\n", index); |
| return -1; |
| } |
| if (ldim_gpio[index].register_flag == 1) { |
| if (lcd_debug_print_flag) { |
| LDIMPR("bl: gpio %s(%d) is already registered\n", |
| ldim_gpio[index].name, index); |
| } |
| return 0; |
| } |
| |
| ret = dm_gpio_lookup_name(ldim_gpio[index].name, &ldim_gpio[index].gpio); |
| if (ret) { |
| LDIMERR("bl: lookup gpio: wrong name %s\n", ldim_gpio[index].name); |
| return -1; |
| } |
| |
| ret = dm_gpio_request(&ldim_gpio[index].gpio, "aml_lcd_bl"); |
| if (ret) { |
| LDIMERR("bl: request gpio %s(%d) failed\n", ldim_gpio[index].name, index); |
| return -1; |
| } |
| |
| if (lcd_debug_print_flag) |
| LDIMPR("bl: request gpio: %s(%d)\n", ldim_gpio[index].name, index); |
| ldim_gpio[index].register_flag = 1; |
| |
| return 0; |
| } |
| |
| int ldim_gpio_set(int index, int value) |
| { |
| int ret = 0; |
| |
| if (index >= BL_GPIO_NUM_MAX) { |
| LDIMERR("bl: %s: invalid gpio: %d\n", __func__, index); |
| return -1; |
| } |
| if (ldim_gpio[index].register_flag == 0) { |
| ret = ldim_gpio_request(index); |
| if (ret) |
| return -1; |
| } |
| |
| switch (value) { |
| case LCD_GPIO_OUTPUT_LOW: |
| ret = dm_gpio_set_dir_flags(&ldim_gpio[index].gpio, GPIOD_IS_OUT); |
| if (ret) { |
| LDIMERR("bl: set gpio %s(%d) direction failed\n", |
| ldim_gpio[index].name, index); |
| return ret; |
| } |
| dm_gpio_set_value(&ldim_gpio[index].gpio, 0); |
| break; |
| case LCD_GPIO_OUTPUT_HIGH: |
| ret = dm_gpio_set_dir_flags(&ldim_gpio[index].gpio, GPIOD_IS_OUT); |
| if (ret) { |
| LDIMERR("bl: set gpio %s(%d) direction failed\n", |
| ldim_gpio[index].name, index); |
| return ret; |
| } |
| dm_gpio_set_value(&ldim_gpio[index].gpio, 1); |
| break; |
| case LCD_GPIO_INPUT: |
| default: |
| ret = dm_gpio_set_dir_flags(&ldim_gpio[index].gpio, GPIOD_IS_IN); |
| if (ret) { |
| LDIMERR("bl: set gpio %s(%d) direction failed\n", |
| ldim_gpio[index].name, index); |
| return ret; |
| } |
| break; |
| } |
| if (lcd_debug_print_flag) { |
| LDIMPR("bl: gpio: %s(%d), value: %d\n", |
| ldim_gpio[index].name, index, value); |
| } |
| |
| return 0; |
| } |
| |
| unsigned int ldim_gpio_input_get(int index) |
| { |
| int ret; |
| unsigned int value; |
| |
| if (index >= BL_GPIO_NUM_MAX) { |
| LDIMERR("%s: invalid gpio: %d\n", __func__, index); |
| return 0; |
| } |
| if (ldim_gpio[index].register_flag == 0) { |
| ret = ldim_gpio_request(index); |
| if (ret) |
| return 0; |
| } |
| |
| value = dm_gpio_get_value(&ldim_gpio[index].gpio); |
| |
| return value; |
| } |
| /* *************************************** */ |
| |
| static unsigned int pwm_reg[6] = { |
| PWM_PWM_A, |
| PWM_PWM_B, |
| PWM_PWM_C, |
| PWM_PWM_D, |
| PWM_PWM_E, |
| PWM_PWM_F, |
| }; |
| |
| void ldim_set_duty_pwm(struct bl_pwm_config_s *bl_pwm) |
| { |
| unsigned int pwm_hi = 0, pwm_lo = 0; |
| unsigned int port = bl_pwm->pwm_port; |
| unsigned int vs[4], ve[4], sw, n, i; |
| |
| bl_pwm->pwm_level = bl_pwm->pwm_cnt * bl_pwm->pwm_duty / 100; |
| |
| LDIMPR("pwm port %d: duty=%d%%, duty_max=%d, duty_min=%d\n", |
| bl_pwm->pwm_port, bl_pwm->pwm_duty, |
| bl_pwm->pwm_duty_max, bl_pwm->pwm_duty_min); |
| |
| switch (bl_pwm->pwm_method) { |
| case BL_PWM_POSITIVE: |
| pwm_hi = bl_pwm->pwm_level; |
| pwm_lo = bl_pwm->pwm_cnt - bl_pwm->pwm_level; |
| break; |
| case BL_PWM_NEGATIVE: |
| pwm_lo = bl_pwm->pwm_level; |
| pwm_hi = bl_pwm->pwm_cnt - bl_pwm->pwm_level; |
| break; |
| default: |
| LDIMERR("port %d: invalid pwm_method %d\n", |
| port, bl_pwm->pwm_method); |
| break; |
| } |
| LDIMPR("port %d: pwm_cnt=%d, pwm_hi=%d, pwm_lo=%d\n", |
| port, bl_pwm->pwm_cnt, pwm_hi, pwm_lo); |
| |
| switch (port) { |
| case BL_PWM_A: |
| case BL_PWM_B: |
| case BL_PWM_C: |
| case BL_PWM_D: |
| case BL_PWM_E: |
| case BL_PWM_F: |
| lcd_cbus_write(pwm_reg[port], (pwm_hi << 16) | pwm_lo); |
| break; |
| case BL_PWM_VS: |
| memset(vs, 0xffff, sizeof(unsigned int) * 4); |
| memset(ve, 0xffff, sizeof(unsigned int) * 4); |
| n = bl_pwm->pwm_freq; |
| sw = (bl_pwm->pwm_cnt * 10 / n + 5) / 10; |
| pwm_hi = (pwm_hi * 10 / n + 5) / 10; |
| pwm_hi = (pwm_hi > 1) ? pwm_hi : 1; |
| if (lcd_debug_print_flag) |
| LDIMPR("n=%d, sw=%d, pwm_high=%d\n", n, sw, pwm_hi); |
| for (i = 0; i < n; i++) { |
| vs[i] = 1 + (sw * i); |
| ve[i] = vs[i] + pwm_hi - 1; |
| if (lcd_debug_print_flag) |
| LDIMPR("vs[%d]=%d, ve[%d]=%d\n", i, vs[i], i, ve[i]); |
| } |
| lcd_vcbus_write(VPU_VPU_PWM_V0, (ve[0] << 16) | (vs[0])); |
| lcd_vcbus_write(VPU_VPU_PWM_V1, (ve[1] << 16) | (vs[1])); |
| lcd_vcbus_write(VPU_VPU_PWM_V2, (ve[2] << 16) | (vs[2])); |
| lcd_vcbus_write(VPU_VPU_PWM_V3, (ve[3] << 16) | (vs[3])); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* set ldim pwm_vs */ |
| static int ldim_pwm_pinmux_ctrl(int status) |
| { |
| struct bl_pwm_config_s *ld_pwm = &ldim_dev_config->pwm_config; |
| int i; |
| |
| if (ld_pwm->pwm_port >= BL_PWM_MAX) |
| return 0; |
| |
| if (lcd_debug_print_flag) |
| LDIMPR("%s: %d\n", __func__, status); |
| |
| if (status) { |
| bl_pwm_ctrl(ld_pwm, 1); |
| /* set pinmux */ |
| ld_pwm->pinmux_flag = 1; |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (ld_pwm->pinmux_clr[i][0] == LCD_PINMUX_END) |
| break; |
| lcd_pinmux_clr_mask(ld_pwm->pinmux_clr[i][0], |
| ld_pwm->pinmux_clr[i][1]); |
| if (lcd_debug_print_flag) { |
| LDIMPR("%s: port=%d, pinmux_clr=%d,0x%08x\n", |
| __func__, ld_pwm->pwm_port, |
| ld_pwm->pinmux_clr[i][0], |
| ld_pwm->pinmux_clr[i][1]); |
| } |
| i++; |
| } |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (ld_pwm->pinmux_set[i][0] == LCD_PINMUX_END) |
| break; |
| lcd_pinmux_set_mask(ld_pwm->pinmux_set[i][0], |
| ld_pwm->pinmux_set[i][1]); |
| if (lcd_debug_print_flag) { |
| LDIMPR("%s: port=%d, pinmux_set=%d,0x%08x\n", |
| __func__, ld_pwm->pwm_port, |
| ld_pwm->pinmux_set[i][0], |
| ld_pwm->pinmux_set[i][1]); |
| } |
| i++; |
| } |
| } else { |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (ld_pwm->pinmux_set[i][0] == LCD_PINMUX_END) |
| break; |
| lcd_pinmux_clr_mask(ld_pwm->pinmux_set[i][0], |
| ld_pwm->pinmux_set[i][1]); |
| if (lcd_debug_print_flag) { |
| LDIMPR("%s: port=%d, pinmux_clr=%d,0x%08x\n", |
| __func__, ld_pwm->pwm_port, |
| ld_pwm->pinmux_set[i][0], |
| ld_pwm->pinmux_set[i][1]); |
| } |
| i++; |
| } |
| ld_pwm->pinmux_flag = 0; |
| |
| bl_pwm_ctrl(ld_pwm, 0); |
| } |
| |
| return 0; |
| } |
| |
| static void ldim_dev_init_table_dynamic_size_print( |
| struct ldim_dev_config_s *ldconf, int flag) |
| { |
| int i, j, max_len; |
| unsigned char cmd_size; |
| unsigned char *table; |
| |
| if (flag) { |
| printf("power on:\n"); |
| table = ldconf->init_on; |
| max_len = ldconf->init_on_cnt; |
| } else { |
| printf("power off:\n"); |
| table = ldconf->init_off; |
| max_len = ldconf->init_off_cnt; |
| } |
| if (table == NULL) { |
| LDIMERR("init_table %d is NULL\n", flag); |
| return; |
| } |
| |
| i = 0; |
| while ((i + 1) < max_len) { |
| if (table[i] == LCD_EXT_CMD_TYPE_END) { |
| printf(" 0x%02x,%d,\n", table[i], table[i+1]); |
| break; |
| } |
| cmd_size = table[i+1]; |
| printf(" 0x%02x,%d,", table[i], cmd_size); |
| if (cmd_size == 0) |
| goto init_table_dynamic_print_next; |
| if (i + 2 + cmd_size > max_len) { |
| printf("cmd_size out of support\n"); |
| break; |
| } |
| |
| if (table[i] == LCD_EXT_CMD_TYPE_DELAY) { |
| for (j = 0; j < cmd_size; j++) |
| printf("%d,", table[i+2+j]); |
| } else if (table[i] == LCD_EXT_CMD_TYPE_CMD) { |
| for (j = 0; j < cmd_size; j++) |
| printf("0x%02x,", table[i+2+j]); |
| } else if (table[i] == LCD_EXT_CMD_TYPE_CMD_DELAY) { |
| for (j = 0; j < (cmd_size - 1); j++) |
| printf("0x%02x,", table[i+2+j]); |
| printf("%d,", table[i+cmd_size+1]); |
| } else { |
| for (j = 0; j < cmd_size; j++) |
| printf("0x%02x,", table[i+2+j]); |
| } |
| init_table_dynamic_print_next: |
| printf("\n"); |
| i += (cmd_size + 2); |
| } |
| } |
| |
| static void ldim_dev_init_table_fixed_size_print( |
| struct ldim_dev_config_s *ldconf, int flag) |
| { |
| int i, j, max_len; |
| unsigned char cmd_size; |
| unsigned char *table; |
| |
| cmd_size = ldconf->cmd_size; |
| if (flag) { |
| printf("power on:\n"); |
| table = ldconf->init_on; |
| max_len = ldconf->init_on_cnt; |
| } else { |
| printf("power off:\n"); |
| table = ldconf->init_off; |
| max_len = ldconf->init_off_cnt; |
| } |
| if (table == NULL) { |
| LDIMERR("init_table %d is NULL\n", flag); |
| return; |
| } |
| |
| i = 0; |
| while ((i + cmd_size) <= max_len) { |
| printf(" "); |
| for (j = 0; j < cmd_size; j++) |
| printf("0x%02x,", table[i+j]); |
| printf("\n"); |
| |
| if (table[i] == LCD_EXT_CMD_TYPE_END) |
| break; |
| i += cmd_size; |
| } |
| } |
| |
| static void ldim_device_config_print(void) |
| { |
| struct bl_pwm_config_s *ld_pwm; |
| |
| if (ldim_dev_config == NULL) { |
| LDIMERR("%s: ldim_dev_config is null\n", __func__); |
| return; |
| } |
| ld_pwm = &ldim_dev_config->pwm_config; |
| |
| printf("dev_name = %s\n" |
| "en_gpio = %d\n" |
| "en_gpio_on = %d\n" |
| "en_gpio_off = %d\n" |
| "dim_max = 0x%03x\n" |
| "dim_min = 0x%03x\n" |
| "region_num = %d\n", |
| ldim_dev_config->name, |
| ldim_dev_config->en_gpio, |
| ldim_dev_config->en_gpio_on, |
| ldim_dev_config->en_gpio_off, |
| ldim_dev_config->dim_min, |
| ldim_dev_config->dim_max, |
| ldim_dev_config->bl_regnum); |
| |
| switch (ldim_dev_config->type) { |
| case LDIM_DEV_TYPE_SPI: |
| printf("spi_pointer = 0x%p\n" |
| "spi_modalias = %s\n" |
| "spi_mode = %d\n" |
| "spi_max_speed_hz = %d\n" |
| "spi_bus_num = %d\n" |
| "spi_chip_select = %d\n" |
| "cs_hold_delay = %d\n" |
| "cs_clk_delay = %d\n" |
| "write_check = %d\n", |
| ldim_spi_info.spi, |
| ldim_spi_info.modalias, |
| ldim_spi_info.mode, |
| ldim_spi_info.max_speed_hz, |
| ldim_spi_info.bus_num, |
| ldim_spi_info.chip_select, |
| ldim_dev_config->cs_hold_delay, |
| ldim_dev_config->cs_clk_delay, |
| ldim_dev_config->write_check); |
| break; |
| case LDIM_DEV_TYPE_I2C: |
| break; |
| case LDIM_DEV_TYPE_NORMAL: |
| default: |
| break; |
| } |
| if (ld_pwm->pwm_port < BL_PWM_MAX) { |
| printf("pwm_port = %d\n" |
| "pwm_pol = %d\n" |
| "pwm_freq = %d\n" |
| "pwm_duty = %d%%\n" |
| "pinmux_flag = %d\n", |
| ld_pwm->pwm_port, ld_pwm->pwm_method, |
| ld_pwm->pwm_freq, ld_pwm->pwm_duty, |
| ld_pwm->pinmux_flag); |
| } |
| |
| if (ldim_dev_config->cmd_size > 0) { |
| printf("init_loaded = %d\n" |
| "cmd_size = %d\n" |
| "init_on_cnt = %d\n" |
| "init_off_cnt = %d\n", |
| ldim_dev_config->init_loaded, |
| ldim_dev_config->cmd_size, |
| ldim_dev_config->init_on_cnt, |
| ldim_dev_config->init_off_cnt); |
| if (ldim_dev_config->cmd_size == LCD_EXT_CMD_SIZE_DYNAMIC) { |
| ldim_dev_init_table_dynamic_size_print(ldim_dev_config, 1); |
| ldim_dev_init_table_dynamic_size_print(ldim_dev_config, 0); |
| } else { |
| ldim_dev_init_table_fixed_size_print(ldim_dev_config, 1); |
| ldim_dev_init_table_fixed_size_print(ldim_dev_config, 0); |
| } |
| } |
| } |
| |
| static int ldim_pinmux_load_from_bsp(struct ldim_dev_config_s *ldev_conf) |
| { |
| char propname[50] = "ldim_pwm_vs_pin"; |
| unsigned int i, j; |
| int set_cnt = 0, clr_cnt = 0; |
| struct bl_pwm_config_s *ld_pwm = &ldev_conf->pwm_config; |
| |
| for (i = 0; i < 2; i++) { |
| if (strncmp(ldev_conf->ldim_pinmux->name, "invalid", 7) == 0) |
| break; |
| if (strncmp(ldev_conf->ldim_pinmux->name, propname, strlen(propname)) == 0) { |
| for (j = 0; j < LCD_PINMUX_NUM; j++ ) { |
| if (ldev_conf->ldim_pinmux->pinmux_set[j][0] == LCD_PINMUX_END) |
| break; |
| ld_pwm->pinmux_set[j][0] = ldev_conf->ldim_pinmux->pinmux_set[j][0]; |
| ld_pwm->pinmux_set[j][1] = ldev_conf->ldim_pinmux->pinmux_set[j][1]; |
| set_cnt++; |
| } |
| for (j = 0; j < LCD_PINMUX_NUM; j++ ) { |
| if (ldev_conf->ldim_pinmux->pinmux_clr[j][0] == LCD_PINMUX_END) |
| break; |
| ld_pwm->pinmux_clr[j][0] = ldev_conf->ldim_pinmux->pinmux_clr[j][0]; |
| ld_pwm->pinmux_clr[j][1] = ldev_conf->ldim_pinmux->pinmux_clr[j][1]; |
| clr_cnt++; |
| } |
| break; |
| } |
| ldev_conf->ldim_pinmux++; |
| } |
| if (set_cnt < LCD_PINMUX_NUM) { |
| ld_pwm->pinmux_set[set_cnt][0] = LCD_PINMUX_END; |
| ld_pwm->pinmux_set[set_cnt][1] = 0x0; |
| } |
| if (clr_cnt < LCD_PINMUX_NUM) { |
| ld_pwm->pinmux_clr[clr_cnt][0] = LCD_PINMUX_END; |
| ld_pwm->pinmux_clr[clr_cnt][1] = 0x0; |
| } |
| |
| if (lcd_debug_print_flag) { |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (ld_pwm->pinmux_set[i][0] == LCD_PINMUX_END) |
| break; |
| LDIMPR("ldim_pinmux set: %d, 0x%08x\n", |
| ld_pwm->pinmux_set[i][0], ld_pwm->pinmux_set[i][1]); |
| i++; |
| } |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (ld_pwm->pinmux_clr[i][0] == LCD_PINMUX_END) |
| break; |
| LDIMPR("ldim_pinmux clr: %d, 0x%08x\n", |
| ld_pwm->pinmux_clr[i][0], ld_pwm->pinmux_clr[i][1]); |
| i++; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int ldim_dev_init_table_dynamic_size_load_dts(const void *dt_blob, |
| int nodeoffset, struct ldim_dev_config_s *ldconf, int flag) |
| { |
| unsigned char cmd_size, type; |
| int i = 0, j, max_len; |
| unsigned char *table; |
| char propname[20]; |
| char *propdata; |
| |
| if (flag) { |
| table = ldconf->init_on; |
| max_len = LDIM_INIT_ON_MAX; |
| sprintf(propname, "init_on"); |
| } else { |
| table = ldconf->init_off; |
| max_len = LDIM_INIT_OFF_MAX; |
| sprintf(propname, "init_off"); |
| } |
| if (table == NULL) { |
| LDIMERR("%s init_table is null\n", propname); |
| return 0; |
| } |
| |
| propdata = (char *)fdt_getprop(dt_blob, nodeoffset, propname, NULL); |
| if (propdata == NULL) { |
| LDIMERR("%s: get %s failed\n", ldconf->name, propname); |
| table[0] = LCD_EXT_CMD_TYPE_END; |
| table[1] = 0; |
| return -1; |
| } |
| |
| while ((i + 1) < max_len) { |
| table[i] = (unsigned char)(be32_to_cpup((((u32*)propdata)+i))); |
| table[i+1] = (unsigned char)(be32_to_cpup((((u32*)propdata)+i+1))); |
| type = table[i]; |
| cmd_size = table[i+1]; |
| if (type == LCD_EXT_CMD_TYPE_END) |
| break; |
| if (cmd_size == 0) |
| goto init_table_dynamic_dts_next; |
| if ((i + 2 + cmd_size) > max_len) { |
| LDIMERR("%s: %s cmd_size out of support\n", ldconf->name, propname); |
| table[i] = LCD_EXT_CMD_TYPE_END; |
| table[i+1] = 0; |
| return -1; |
| } |
| for (j = 0; j < cmd_size; j++) |
| table[i+2+j] = (unsigned char)(be32_to_cpup((((u32*)propdata)+i+2+j))); |
| |
| init_table_dynamic_dts_next: |
| i += (cmd_size + 2); |
| } |
| if (flag) |
| ldconf->init_on_cnt = i + 2; |
| else |
| ldconf->init_off_cnt = i + 2; |
| |
| return 0; |
| } |
| |
| static int ldim_dev_init_table_fixed_size_load_dts(const void *dt_blob, |
| int nodeoffset, struct ldim_dev_config_s *ldconf, int flag) |
| { |
| unsigned char cmd_size; |
| int i = 0, j, max_len; |
| unsigned char *table; |
| char propname[20]; |
| char *propdata; |
| |
| cmd_size = ldconf->cmd_size; |
| if (flag) { |
| table = ldconf->init_on; |
| max_len = LDIM_INIT_ON_MAX; |
| sprintf(propname, "init_on"); |
| } else { |
| table = ldconf->init_off; |
| max_len = LDIM_INIT_OFF_MAX; |
| sprintf(propname, "init_off"); |
| } |
| if (table == NULL) { |
| LDIMPR("%s init_table is null\n", propname); |
| return 0; |
| } |
| |
| propdata = (char *)fdt_getprop(dt_blob, nodeoffset, propname, NULL); |
| if (propdata == NULL) { |
| LDIMERR("%s: get %s failed\n", ldconf->name, propname); |
| table[0] = LCD_EXT_CMD_TYPE_END; |
| table[1] = 0; |
| return -1; |
| } |
| |
| while (i < max_len) { |
| if ((i + cmd_size) > max_len) { |
| LDIMERR("%s: %s cmd_size out of support\n", ldconf->name, propname); |
| table[i] = LCD_EXT_CMD_TYPE_END; |
| return -1; |
| } |
| for (j = 0; j < cmd_size; j++) |
| table[i+j] = (unsigned char)(be32_to_cpup((((u32*)propdata)+i+j))); |
| |
| if (table[i] == LCD_EXT_CMD_TYPE_END) |
| break; |
| |
| i += cmd_size; |
| } |
| if (flag) |
| ldconf->init_on_cnt = i + cmd_size; |
| else |
| ldconf->init_off_cnt = i + cmd_size; |
| |
| return 0; |
| } |
| |
| static int ldim_dev_get_config_from_dts(char *dt_addr, int index) |
| { |
| int parent_offset, child_offset; |
| char propname[30]; |
| char *propdata; |
| char *p; |
| const char *str; |
| int temp; |
| struct bl_pwm_config_s *ld_pwm = &ldim_dev_config->pwm_config; |
| struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); |
| int i, j; |
| int ret = 0; |
| |
| strcpy(ldim_dev_config->name, "ldim_dev"); |
| memset(ldim_dev_config->init_on, 0, LDIM_INIT_ON_MAX); |
| memset(ldim_dev_config->init_off, 0, LDIM_INIT_OFF_MAX); |
| ldim_dev_config->init_on[0] = 0xff; |
| ldim_dev_config->init_off[0] = 0xff; |
| |
| if (dt_addr == NULL) { |
| LDIMERR("%s: dt_addr is NULL\n", __func__); |
| return -1; |
| } |
| |
| parent_offset = fdt_path_offset(dt_addr, "/local_dimming_device"); |
| if (parent_offset < 0) { |
| parent_offset = fdt_path_offset(dt_addr, "/local_diming_device"); |
| if (parent_offset < 0) { |
| LDIMERR("not find /local_dimming_device node: %s\n", |
| fdt_strerror(parent_offset)); |
| return -1; |
| } |
| } |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "status", NULL); |
| if (propdata == NULL) { |
| LDIMERR("not find local_dimming_device status, default to disabled\n"); |
| return -1; |
| } else { |
| if (strncmp(propdata, "okay", 2)) { |
| LDIMPR("local_dimming_device status disabled\n"); |
| return -1; |
| } |
| } |
| |
| /* init gpio */ |
| i = 0; |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "ldim_dev_gpio_names", NULL); |
| if (propdata == NULL) { |
| LDIMERR("failed to get ldim_dev_gpio_names\n"); |
| } else { |
| p = propdata; |
| while (i < BL_GPIO_NUM_MAX) { |
| if (i > 0) |
| p += strlen(p) + 1; |
| str = p; |
| if (strlen(str) == 0) |
| break; |
| ldim_gpio_probe(str, i); |
| i++; |
| } |
| } |
| |
| /* get device config */ |
| sprintf(propname,"/local_dimming_device/ldim_dev_%d", index); |
| child_offset = fdt_path_offset(dt_addr, propname); |
| if (child_offset < 0) { |
| sprintf(propname,"/local_diming_device/ldim_dev_%d", index); |
| child_offset = fdt_path_offset(dt_addr, propname); |
| if (child_offset < 0) { |
| LDIMERR("not find %s node: %s\n", |
| propname, fdt_strerror(child_offset)); |
| return -1; |
| } |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "ldim_dev_name", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get ldim_dev_name\n"); |
| else |
| strcpy(ldim_dev_config->name, propdata); |
| LDIMPR("get config: %s(%d)\n", ldim_dev_config->name, index); |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "ldim_pwm_port", NULL); |
| if (propdata == NULL) { |
| LDIMERR("failed to get ldim_pwm_port\n"); |
| ld_pwm->pwm_port = BL_PWM_MAX; |
| } else { |
| ld_pwm->pwm_port = bl_pwm_str_to_pwm(propdata); |
| } |
| LDIMPR("pwm_port: %s(%u)\n", propdata, ld_pwm->pwm_port); |
| if (ld_pwm->pwm_port < BL_PWM_MAX) { |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "ldim_pwm_attr", NULL); |
| if (propdata == NULL) { |
| LDIMERR("failed to get ldim_pwm_attr\n"); |
| ld_pwm->pwm_method = BL_PWM_POSITIVE; |
| if (ld_pwm->pwm_port == BL_PWM_VS) |
| ld_pwm->pwm_freq = 1; |
| else |
| ld_pwm->pwm_freq = 60; |
| ld_pwm->pwm_duty = 50; |
| } else { |
| ld_pwm->pwm_method = be32_to_cpup((u32*)propdata); |
| ld_pwm->pwm_freq = be32_to_cpup((((u32*)propdata)+1)); |
| ld_pwm->pwm_duty = be32_to_cpup((((u32*)propdata)+2)); |
| } |
| if (ld_pwm->pwm_port == BL_PWM_VS) { |
| if (ld_pwm->pwm_freq > 4) { |
| LDIMERR("pwm_vs wrong freq %d\n", ld_pwm->pwm_freq); |
| ld_pwm->pwm_freq = BL_FREQ_VS_DEFAULT; |
| } |
| } else { |
| if (ld_pwm->pwm_freq > XTAL_HALF_FREQ_HZ) |
| ld_pwm->pwm_freq = XTAL_HALF_FREQ_HZ; |
| } |
| LDIMPR("get pwm pol = %d, freq = %d, duty = %d%%\n", |
| ld_pwm->pwm_method, ld_pwm->pwm_freq, ld_pwm->pwm_duty); |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "en_gpio_on_off", NULL); |
| if (propdata == NULL) { |
| LDIMERR("failed to get en_gpio_on_off\n"); |
| } else { |
| ldim_dev_config->en_gpio = be32_to_cpup((u32*)propdata); |
| ldim_dev_config->en_gpio_on = be32_to_cpup((((u32*)propdata)+1)); |
| ldim_dev_config->en_gpio_off = be32_to_cpup((((u32*)propdata)+2)); |
| } |
| if (lcd_debug_print_flag) { |
| LDIMPR("en_gpio=%s(%d), en_gpio_on=%d, en_gpio_off=%d\n", |
| ldim_dev_config->gpio_name[ldim_dev_config->en_gpio], |
| ldim_dev_config->en_gpio, ldim_dev_config->en_gpio_on, |
| ldim_dev_config->en_gpio_off); |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "dim_max_min", NULL); |
| if (propdata == NULL) { |
| LDIMERR("failed to get dim_max_min\n"); |
| } else { |
| ldim_dev_config->dim_max = be32_to_cpup((u32*)propdata); |
| ldim_dev_config->dim_min = be32_to_cpup((((u32*)propdata)+1)); |
| } |
| if (lcd_debug_print_flag) { |
| LDIMPR("dim_max=0x%03x, dim_min=0x%03x\n", |
| ldim_dev_config->dim_max, ldim_dev_config->dim_min); |
| } |
| |
| temp = ldim_drv->ldim_conf->row * ldim_drv->ldim_conf->col; |
| ldim_dev_config->bl_regnum = (unsigned short)temp; |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "type", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get type\n"); |
| else { |
| ldim_dev_config->type = be32_to_cpup((u32*)propdata); |
| LDIMPR("type: %d\n", ldim_dev_config->type); |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "ldim_pwm_pinmux_sel", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get ldim_pwm_name\n"); |
| else |
| strcpy(ldim_dev_config->pinmux_name, propdata); |
| LDIMPR("ldim_pwm_pinmux_sel: %s\n", ldim_dev_config->pinmux_name); |
| |
| if (ldim_dev_config->type >= LDIM_DEV_TYPE_MAX) { |
| LDIMERR("type num is out of support\n"); |
| return -1; |
| } |
| |
| switch (ldim_dev_config->type) { |
| case LDIM_DEV_TYPE_SPI: |
| ldim_drv->spi_info = &ldim_spi_info; |
| /* get spi config */ |
| /* |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "spi_bus_num", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get spi_bus_num\n"); |
| else |
| ldim_spi_info.bus_num = be32_to_cpup((u32*)propdata); |
| */ |
| ldim_spi_info.bus_num = 0; /* fix value */ |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "spi_chip_select", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get spi_chip_select\n"); |
| else |
| ldim_spi_info.chip_select = be32_to_cpup((u32*)propdata); |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "spi_max_frequency", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get spi_max_frequency\n"); |
| else |
| ldim_spi_info.max_speed_hz = be32_to_cpup((u32*)propdata); |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "spi_mode", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get spi_mode\n"); |
| else |
| ldim_spi_info.mode = be32_to_cpup((u32*)propdata); |
| |
| if (lcd_debug_print_flag) { |
| LDIMPR("spi bus_num=%d, chip_select=%d, max_frequency=%d, mode=%d\n", |
| ldim_spi_info.bus_num, ldim_spi_info.chip_select, |
| ldim_spi_info.max_speed_hz, ldim_spi_info.mode); |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "spi_cs_delay", NULL); |
| if (propdata == NULL) { |
| LDIMERR("failed to get spi_cs_delay\n"); |
| } else { |
| ldim_dev_config->cs_hold_delay = be32_to_cpup((u32*)propdata); |
| ldim_dev_config->cs_clk_delay = be32_to_cpup((((u32*)propdata)+1)); |
| } |
| if (lcd_debug_print_flag) { |
| LDIMPR("cs_hold_delay=%dus, cs_clk_delay=%dus\n", |
| ldim_dev_config->cs_hold_delay, ldim_dev_config->cs_clk_delay); |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "spi_write_check", NULL); |
| if (propdata == NULL) |
| LDIMERR("failed to get spi_write_check\n"); |
| else |
| ldim_dev_config->write_check = (unsigned char)(be32_to_cpup((u32*)propdata)); |
| if (lcd_debug_print_flag) |
| LDIMPR("write_check=%d\n", ldim_dev_config->write_check); |
| |
| /* get init_cmd */ |
| propdata = (char *)fdt_getprop(dt_addr, child_offset, "cmd_size", NULL); |
| if (propdata == NULL) { |
| LDIMPR("no cmd_size\n"); |
| ldim_dev_config->cmd_size = 0; |
| } else { |
| temp = be32_to_cpup((u32*)propdata); |
| ldim_dev_config->cmd_size = (unsigned char)temp; |
| } |
| if (lcd_debug_print_flag) |
| LDIMPR("cmd_size=%d\n", ldim_dev_config->cmd_size); |
| if (ldim_dev_config->cmd_size == 0) |
| break; |
| |
| if (ldim_dev_config->cmd_size == LCD_EXT_CMD_SIZE_DYNAMIC) { |
| ret = ldim_dev_init_table_dynamic_size_load_dts( |
| dt_addr, child_offset, ldim_dev_config, 1); |
| if (ret) |
| break; |
| ret = ldim_dev_init_table_dynamic_size_load_dts( |
| dt_addr, child_offset, ldim_dev_config, 0); |
| } else { |
| ret = ldim_dev_init_table_fixed_size_load_dts( |
| dt_addr, child_offset, ldim_dev_config, 1); |
| if (ret) |
| break; |
| ret = ldim_dev_init_table_fixed_size_load_dts( |
| dt_addr, child_offset, ldim_dev_config, 0); |
| } |
| if (ret == 0) |
| ldim_dev_config->init_loaded = 1; |
| break; |
| case LDIM_DEV_TYPE_I2C: |
| break; |
| case LDIM_DEV_TYPE_NORMAL: |
| default: |
| break; |
| } |
| |
| /* pinmux */ |
| ret = ldim_pinmux_load_from_bsp(ldim_drv->ldev_conf); |
| |
| return ret; |
| } |
| |
| static int ldim_dev_add_driver(struct aml_ldim_driver_s *ldim_drv) |
| { |
| struct ldim_dev_config_s *ldev_conf = ldim_drv->ldev_conf; |
| int index = ldim_drv->dev_index; |
| int ret = -1; |
| |
| switch (ldev_conf->type) { |
| case LDIM_DEV_TYPE_SPI: |
| ret = ldim_spi_driver_add(ldim_drv); |
| break; |
| case LDIM_DEV_TYPE_I2C: |
| break; |
| case LDIM_DEV_TYPE_NORMAL: |
| default: |
| break; |
| } |
| if (ret) |
| return -1; |
| |
| ret = -1; |
| if (strcmp(ldev_conf->name, "global") == 0) { |
| #ifdef CONFIG_AML_LOCAL_DIMMING_GLOBAL |
| ret = ldim_dev_global_probe(ldim_drv); |
| #endif |
| } else if (strcmp(ldev_conf->name, "iw7027") == 0) { |
| #ifdef CONFIG_AML_LOCAL_DIMMING_IW7027 |
| ret = ldim_dev_iw7027_probe(ldim_drv); |
| #endif |
| } else if (strcmp(ldev_conf->name, "ob3350") == 0) { |
| #ifdef CONFIG_AML_LOCAL_DIMMING_OB3350 |
| ret = ldim_dev_ob3350_probe(ldim_drv); |
| #endif |
| } else { |
| LDIMERR("invalid device name: %s\n", ldev_conf->name); |
| } |
| |
| if (ret) { |
| LDIMERR("add device driver failed: %s(%d)\n", |
| ldev_conf->name, index); |
| } else { |
| ldim_dev_probe_flag = 1; |
| LDIMPR("add device driver: %s(%d)\n", ldev_conf->name, index); |
| } |
| |
| return ret; |
| } |
| |
| static int ldim_dev_remove_driver(struct aml_ldim_driver_s *ldim_drv) |
| { |
| struct ldim_dev_config_s *ldev_conf = ldim_drv->ldev_conf; |
| int index = ldim_drv->dev_index; |
| int ret = -1; |
| |
| if (ldim_dev_probe_flag == 0) |
| return 0; |
| |
| if (strcmp(ldev_conf->name, "global") == 0) { |
| #ifdef CONFIG_AML_LOCAL_DIMMING_GLOBAL |
| ret = ldim_dev_global_remove(ldim_drv); |
| #endif |
| } else if (strcmp(ldev_conf->name, "iw7027") == 0) { |
| #ifdef CONFIG_AML_LOCAL_DIMMING_IW7027 |
| ret = ldim_dev_iw7027_remove(ldim_drv); |
| #endif |
| } else if (strcmp(ldev_conf->name, "ob3350") == 0) { |
| #ifdef CONFIG_AML_LOCAL_DIMMING_OB3350 |
| ret = ldim_dev_ob3350_remove(ldim_drv); |
| #endif |
| } else { |
| LDIMERR("invalid device name: %s\n", ldev_conf->name); |
| ret = -1; |
| } |
| |
| if (ret) { |
| LDIMERR("remove device driver failed: %s(%d)\n", |
| ldev_conf->name, index); |
| } else { |
| LDIMPR("remove device driver: %s(%d)\n", ldev_conf->name, index); |
| } |
| |
| return ret; |
| } |
| |
| int aml_ldim_device_probe(char *dt_addr) |
| { |
| struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); |
| int ret = 0; |
| |
| if (lcd_debug_print_flag) |
| LDIMPR("%s\n", __func__); |
| |
| ldim_dev_probe_flag = 0; |
| |
| /* get configs */ |
| ldim_dev_config = &ldim_config_dft; |
| ldim_drv->ldev_conf = ldim_dev_config; |
| ldim_drv->pinmux_ctrl = ldim_pwm_pinmux_ctrl; |
| ldim_drv->device_config_print = ldim_device_config_print; |
| |
| ret = ldim_dev_get_config_from_dts(dt_addr, ldim_drv->dev_index); |
| if (ret) |
| return -1; |
| |
| /* add device driver */ |
| ret = ldim_dev_add_driver(ldim_drv); |
| |
| return ret; |
| } |
| |
| int aml_ldim_device_remove(void) |
| { |
| struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); |
| int ret = 0; |
| |
| ldim_dev_remove_driver(ldim_drv); |
| |
| return ret; |
| } |
| |