From 484d55f899904daa8851c1f642147a0547ea91e0 Mon Sep 17 00:00:00 2001 From: Weiming Liu Date: Thu, 19 Apr 2018 10:16:52 +0800 Subject: [PATCH] ldim: add iw7027 driver PD#164701: ldim: add iw7027 driver Change-Id: I75dd8e802b2eecf2d3d9d2f32935721f1a1bb285 Signed-off-by: Weiming Liu --- MAINTAINERS | 6 + .../boot/dts/amlogic/mesontxlx_r311-panel.dtsi | 53 +- .../amlogic/media/vout/backlight/aml_ldim/Makefile | 2 +- .../media/vout/backlight/aml_ldim/iw7027_bl.c | 687 +++++++++++++++++++++ .../media/vout/backlight/aml_ldim/iw7027_bl.h | 115 ++++ .../media/vout/backlight/aml_ldim/ldim_dev_drv.c | 55 +- .../media/vout/backlight/aml_ldim/ldim_dev_drv.h | 2 + .../media/vout/backlight/aml_ldim/ldim_drv.c | 30 +- include/linux/amlogic/media/vout/lcd/aml_bl.h | 2 + include/linux/amlogic/media/vout/lcd/aml_ldim.h | 2 - 10 files changed, 912 insertions(+), 42 deletions(-) create mode 100644 drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c create mode 100644 drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h diff --git a/MAINTAINERS b/MAINTAINERS index baa1cdd..807f5aa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14427,3 +14427,9 @@ AMLOGIC LCD ADD TVCONFIG SUPPORT M: Evoke Zhang F: drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.dts F: drivers/amlogic/media/vout/lcd/lcd_tablet/aml_lcd.dts + +AMLOGIC ADD LDIM IW7027 DRIVER +M: Weiming Liu +F: drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c +F: drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h + diff --git a/arch/arm64/boot/dts/amlogic/mesontxlx_r311-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesontxlx_r311-panel.dtsi index e99988a..b0308c2 100644 --- a/arch/arm64/boot/dts/amlogic/mesontxlx_r311-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesontxlx_r311-panel.dtsi @@ -636,12 +636,12 @@ bl_power_attr = <0 /*en_gpio_index*/ 1 0 /*on_value, off_value*/ 200 200>; /*on_delay(ms), off_delay(ms)*/ - bl_ldim_region_row_col = <1 8>; + bl_ldim_region_row_col = <1 10>; bl_ldim_mode = <1>; /*1=single_side * (top, bottom, left or right), *2=uniform(top/bottom, left/right) */ - bl_ldim_mapping = <0 1 2 3 4 5 6 7>; + bl_ldim_mapping = <0 1 2 3 4 5 6 7 8 9>; ldim_dev_index = <2>; }; backlight_5{ @@ -681,6 +681,7 @@ pinctrl-names = "ldim_pwm","ldim_pwm_vs"; pinctrl-0 = <&ldim_pwm_pins>; pinctrl-1 = <&ldim_pwm_vs_pins>; + pinctrl_version = <1>; /* for uboot */ /* pwm port: PWM_A, PWM_B, PWM_C, PWM_D, PWM_E, PWM_F, PWM_VS*/ ldim_dev-gpios = <&gpio GPIOZ_12 1 @@ -714,5 +715,53 @@ en_gpio_on_off = <2 /*ldim_dev-gpios index*/ 1 0>; /*on_level, off_level*/ }; + ldim_dev_2 { + index = <1>; + type = <1>; /* 0=normal,1=spi,2=i2c */ + ldim_dev_name = "iw7027"; + ldim_pwm_pinmux_sel = "ldim_pwm_vs"; + ldim_pwm_port = "PWM_VS"; + ldim_pwm_attr = <1 /* pol */ + 2 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/ + 50>;/*duty(%)*/ + spi_bus_num = <0>; + spi_chip_select = <0>; + spi_max_frequency = <400000>; /* unit: hz */ + spi_mode = <0>; /* mode: 0, 1, 2, 3 */ + spi_cs_delay = <10 /* hold_high_delay */ + 100>; /* clk_cs_delay (unit: us) */ + en_gpio_on_off = <0 /* ldim_dev-gpios index */ + 1 /* on_level */ + 0>; /* off_level */ + lamp_err_gpio = <0xff>; + /* ldim_dev-gpios index, 0xff=invalid */ + spi_write_check = <0>; /* 0=disable, 1=enable */ + dim_max_min = <0xfff 0x7f>; /* dim_max, dim_min */ + cmd_size = <4>; + /* init: (type, data..., delay), + * must match cmd_size for every group + */ + /* type: 0x00=cmd, 0xff=ending*/ + /* data: spi data, fill 0x0 for no use */ + /* delay: unit ms */ + init_on = < + 0x00 0x23 0x03 0x00 + 0x00 0x24 0xff 0x00 + 0x00 0x25 0x00 0x00 + 0x00 0x26 0x00 0x00 + 0x00 0x27 0x60 0x00 + 0x00 0x29 0x00 0x00 + 0x00 0x2a 0x00 0x00 + /*0x00 0x2b 0x7f 0x00*/ + 0x00 0x2c 0x73 0x00 + 0x00 0x2d 0x37 0x00 + 0x00 0x31 0x93 0x00 + 0x00 0x32 0x0f 0x00 + 0x00 0x33 0xff 0x00 + 0x00 0x34 0xc8 0x00 + 0x00 0x35 0xbf 0x00 + 0xff 0x00 0x00 0x00>; + }; }; + }; /* end of / */ diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/Makefile b/drivers/amlogic/media/vout/backlight/aml_ldim/Makefile index 2830aa8..5da4662 100644 --- a/drivers/amlogic/media/vout/backlight/aml_ldim/Makefile +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/Makefile @@ -1,7 +1,7 @@ # # Makefile for LDIM. # -obj-$(CONFIG_AMLOGIC_LOCAL_DIMMING) = aml_ldim.o ldim_dev_drv.o ob3350_bl.o global_bl.o +obj-$(CONFIG_AMLOGIC_LOCAL_DIMMING) = aml_ldim.o ldim_dev_drv.o ob3350_bl.o global_bl.o iw7027_bl.o aml_ldim-objs := ldim_drv.o ldim_func.o diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c b/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c new file mode 100644 index 0000000..e6cac94 --- /dev/null +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c @@ -0,0 +1,687 @@ +/* + * drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c + * + * Copyright (C) 2017 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iw7027_bl.h" +#include "ldim_drv.h" +#include "ldim_dev_drv.h" + +#define INT_VIU_VSYNC 35 + +#define NORMAL_MSG (0<<7) +#define BROADCAST_MSG (1<<7) +#define BLOCK_DATA (0<<6) +#define SINGLE_DATA (1<<6) +#define IW7027_DEV_ADDR 1 + +#define IW7027_REG_BRIGHTNESS_CHK 0x00 +#define IW7027_REG_BRIGHTNESS 0x01 +#define IW7027_REG_CHIPID 0x7f +#define IW7027_CHIPID 0x28 + +#define IW7027_POWER_ON 0 +#define IW7027_POWER_RESET 1 +static int iw7027_on_flag; +static int iw7027_spi_op_flag; + +static DEFINE_MUTEX(iw7027_spi_mutex); + +struct iw7027 { + int test_mode; + struct spi_device *spi; + int cs_hold_delay; + int cs_clk_delay; + unsigned char cmd_size; + unsigned char *init_data; + struct class cls; +}; +struct iw7027 *bl_iw7027; + +static int test_brightness[] = {0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff +}; + +static int iw7027_wreg(struct spi_device *spi, u8 addr, u8 val) +{ + u8 tbuf[3]; + int ret; + + mutex_lock(&iw7027_spi_mutex); + + if (bl_iw7027->cs_hold_delay) + udelay(bl_iw7027->cs_hold_delay); + dirspi_start(spi); + if (bl_iw7027->cs_clk_delay) + udelay(bl_iw7027->cs_clk_delay); + tbuf[0] = NORMAL_MSG | SINGLE_DATA | IW7027_DEV_ADDR; + tbuf[1] = addr & 0x7f; + tbuf[2] = val; + ret = dirspi_write(spi, tbuf, 3); + if (bl_iw7027->cs_clk_delay) + udelay(bl_iw7027->cs_clk_delay); + dirspi_stop(spi); + mutex_unlock(&iw7027_spi_mutex); + + return ret; +} + +static int iw7027_rreg(struct spi_device *spi, u8 addr, u8 *val) +{ + u8 tbuf[3]; + int ret; + + if (addr >= 0x80) + iw7027_wreg(bl_iw7027->spi, 0x78, 0x80); + else + iw7027_wreg(bl_iw7027->spi, 0x78, 0x0); + + mutex_lock(&iw7027_spi_mutex); + + if (bl_iw7027->cs_hold_delay) + udelay(bl_iw7027->cs_hold_delay); + dirspi_start(spi); + if (bl_iw7027->cs_clk_delay) + udelay(bl_iw7027->cs_clk_delay); + tbuf[0] = NORMAL_MSG | SINGLE_DATA | IW7027_DEV_ADDR; + tbuf[1] = addr | 0x80; + tbuf[2] = 0; + ret = dirspi_write(spi, tbuf, 3); + ret = dirspi_read(spi, val, 1); + if (bl_iw7027->cs_clk_delay) + udelay(bl_iw7027->cs_clk_delay); + dirspi_stop(spi); + + mutex_unlock(&iw7027_spi_mutex); + + return ret; +} + +static int iw7027_wregs(struct spi_device *spi, u8 addr, u8 *val, int len) +{ + u8 tbuf[30]; + int ret; + + mutex_lock(&iw7027_spi_mutex); + + if (bl_iw7027->cs_hold_delay) + udelay(bl_iw7027->cs_hold_delay); + dirspi_start(spi); + if (bl_iw7027->cs_clk_delay) + udelay(bl_iw7027->cs_clk_delay); + tbuf[0] = NORMAL_MSG | BLOCK_DATA | IW7027_DEV_ADDR; + tbuf[1] = len; + tbuf[2] = addr & 0x7f; + memcpy(&tbuf[3], val, len); + ret = dirspi_write(spi, tbuf, len+3); + if (bl_iw7027->cs_clk_delay) + udelay(bl_iw7027->cs_clk_delay); + dirspi_stop(spi); + + mutex_unlock(&iw7027_spi_mutex); + + return ret; +} + +static int iw7027_power_on_init(int flag) +{ + unsigned char addr, val; + int i, ret = 0; + + LDIMPR("%s: spi_op_flag=%d\n", __func__, iw7027_spi_op_flag); + + if (flag == IW7027_POWER_RESET) + goto iw7027_power_reset_p; + i = 1000; + while ((iw7027_spi_op_flag) && (i > 0)) { + i--; + udelay(10); + } + if (iw7027_spi_op_flag == 1) { + LDIMERR("%s: wait spi idle state failed\n", __func__); + return 0; + } + + iw7027_spi_op_flag = 1; +iw7027_power_reset_p: + + for (i = 0; i < LDIM_SPI_INIT_ON_SIZE; i += bl_iw7027->cmd_size) { + if (bl_iw7027->init_data[i] == 0xff) { + if (bl_iw7027->init_data[i+3] > 0) + mdelay(bl_iw7027->init_data[i+3]); + break; + } else if (bl_iw7027->init_data[i] == 0x0) { + addr = bl_iw7027->init_data[i+1]; + val = bl_iw7027->init_data[i+2]; + ret = iw7027_wreg(bl_iw7027->spi, addr, val); + udelay(1); + } + if (bl_iw7027->init_data[i+3] > 0) + mdelay(bl_iw7027->init_data[i+3]); + } + + if (flag == IW7027_POWER_RESET) + return ret; + + iw7027_spi_op_flag = 0; + return ret; +} + +static int iw7027_hw_init_on(void) +{ + int i, j; + unsigned char temp, reg_chk, reg_duty_chk; + + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + + ldim_gpio_set(ldim_drv->ldev_conf->en_gpio, + ldim_drv->ldev_conf->en_gpio_on); + mdelay(2); + + iw7027_wreg(bl_iw7027->spi, 0x00, 0x06); + + ldim_set_duty_pwm(&(ldim_drv->ldev_conf->pwm_config)); + ldim_drv->pinmux_ctrl(ldim_drv->ldev_conf->pinmux_name); + mdelay(100); + + iw7027_rreg(bl_iw7027->spi, 0x00, ®_chk); + for (i = 1; i < 10; i++) { + iw7027_rreg(bl_iw7027->spi, 0x00, &temp); + if (temp != reg_chk) + goto iw7027_smr_end; + } + + iw7027_power_on_init(IW7027_POWER_ON); + mdelay(500); + iw7027_wreg(bl_iw7027->spi, 0x00, 0x07); + iw7027_rreg(bl_iw7027->spi, 0xb3, ®_duty_chk); + if (reg_duty_chk == 0x05) { + for (j = 0; j < 20; j++) + iw7027_wreg(bl_iw7027->spi, (0x40 + j), 0x1f); + } + +iw7027_smr_end: + iw7027_spi_op_flag = 0; + + return 0; +} + +static int iw7027_hw_init_off(void) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + int i = 1000; + + while ((iw7027_spi_op_flag) && (i > 0)) { + i--; + udelay(10); + } + if (iw7027_spi_op_flag == 1) + LDIMERR("%s: wait spi idle state failed\n", __func__); + + ldim_gpio_set(ldim_drv->ldev_conf->en_gpio, + ldim_drv->ldev_conf->en_gpio_off); + + return 0; +} + +static int iw7027_spi_dump_low(char *buf) +{ + int ret = 0; + unsigned int i; + unsigned char val; + + for (i = 0; i <= 0x7f; i++) { + iw7027_rreg(bl_iw7027->spi, i, &val); + if (buf) { + int n = sprintf(buf+ret, + "iw7027 reg 0x%02x=0x%02x\n", i, val); + ret += n; + } + pr_info("iw7027 reg 0x%02x=0x%02x\n", i, val); + } + if (buf) + ret += sprintf(buf, "\n"); + pr_info("\n"); + + return ret; +} + +static int iw7027_spi_dump_high(char *buf) +{ + int ret = 0; + unsigned int i; + unsigned char val; + + for (i = 0x80; i <= 0xff; i++) { + iw7027_rreg(bl_iw7027->spi, i, &val); + if (buf) { + int n = sprintf(buf+ret, + "iw7027 reg 0x%02x=0x%02x\n", i, val); + ret += n; + } + pr_info("iw7027 reg 0x%02x=0x%02x\n", i, val); + } + if (buf) + ret += sprintf(buf, "\n"); + pr_info("\n"); + + return ret; +} + +static unsigned int iw7027_get_value(unsigned int level) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + unsigned int val; + unsigned int dim_max, dim_min; + + dim_max = ldim_drv->ldev_conf->dim_max; + dim_min = ldim_drv->ldev_conf->dim_min; + + val = dim_min + ((level * (dim_max - dim_min)) / LD_DATA_MAX); + + return val; +} + +static int iw7027_smr(unsigned short *buf, unsigned char len) +{ + int i, j; + unsigned int value_flag = 0; + unsigned char val_0[20]; + + if (iw7027_on_flag == 0) { + if (ldim_debug_print) + LDIMPR("%s: on_flag=%d\n", __func__, iw7027_on_flag); + return 0; + } + if (len != 10) { + LDIMERR("%s: data len %d invalid\n", __func__, len); + return -1; + } + if (iw7027_spi_op_flag) { + if (ldim_debug_print) { + LDIMPR("%s: spi_op_flag=%d\n", + __func__, iw7027_spi_op_flag); + } + return 0; + } + + iw7027_spi_op_flag = 1; + + for (i = 0; i < 10; i++) + value_flag = value_flag || buf[i]; + + if (value_flag) { + if (bl_iw7027->test_mode) { + val_0[0] = (test_brightness[0] & 0xf00) >> 8; + val_0[1] = test_brightness[0] & 0xff; + val_0[2] = (test_brightness[1] & 0xf00) >> 8; + val_0[3] = test_brightness[1] & 0xff; + val_0[4] = (test_brightness[2] & 0xf00) >> 8; + val_0[5] = test_brightness[2] & 0xff; + val_0[6] = (test_brightness[3] & 0xf00) >> 8; + val_0[7] = test_brightness[3] & 0xff; + val_0[8] = (test_brightness[4] & 0xf00) >> 8; + val_0[9] = test_brightness[4] & 0xff; + val_0[10] = (test_brightness[5] & 0xf00) >> 8; + val_0[11] = test_brightness[5] & 0xff; + val_0[12] = (test_brightness[6] & 0xf00) >> 8; + val_0[13] = test_brightness[6] & 0xff; + val_0[14] = (test_brightness[7] & 0xf00) >> 8; + val_0[15] = test_brightness[7] & 0xff; + val_0[16] = (test_brightness[8] & 0xf00) >> 8; + val_0[17] = test_brightness[8] & 0xff; + val_0[18] = (test_brightness[9] & 0xf00) >> 8; + val_0[19] = test_brightness[9] & 0xff; + + iw7027_wregs(bl_iw7027->spi, 0x40, val_0, 20); + } else { + val_0[0] = ((iw7027_get_value(buf[0]) + ) & 0xf00) >> 8; + val_0[1] = (iw7027_get_value(buf[0]) + ) & 0xff; + val_0[2] = ((iw7027_get_value(buf[1]) + ) & 0xf00) >> 8; + val_0[3] = (iw7027_get_value(buf[1]) + ) & 0xff; + val_0[4] = ((iw7027_get_value(buf[2]) + ) & 0xf00) >> 8; + val_0[5] = (iw7027_get_value(buf[2]) + ) & 0xff; + val_0[6] = ((iw7027_get_value(buf[3]) + ) & 0xf00) >> 8; + val_0[7] = (iw7027_get_value(buf[3]) + ) & 0xff; + val_0[8] = ((iw7027_get_value(buf[4]) + ) & 0xf00) >> 8; + val_0[9] = (iw7027_get_value(buf[4]) + ) & 0xff; + val_0[10] = ((iw7027_get_value(buf[5]) + ) & 0xf00) >> 8; + val_0[11] = (iw7027_get_value(buf[5]) + ) & 0xff; + val_0[12] = ((iw7027_get_value(buf[6]) + ) & 0xf00) >> 8; + val_0[13] = (iw7027_get_value(buf[6]) + ) & 0xff; + val_0[14] = ((iw7027_get_value(buf[7]) + ) & 0xf00) >> 8; + val_0[15] = (iw7027_get_value(buf[7]) + ) & 0xff; + val_0[16] = ((iw7027_get_value(buf[8]) + ) & 0xf00) >> 8; + val_0[17] = (iw7027_get_value(buf[8]) + ) & 0xff; + val_0[18] = ((iw7027_get_value(buf[9]) + ) & 0xf00) >> 8; + val_0[19] = (iw7027_get_value(buf[9]) + ) & 0xff; + + iw7027_wregs(bl_iw7027->spi, 0x40, val_0, 20); + } + } else { + for (j = 0; j < 20; j++) + val_0[j] = 0; + iw7027_wregs(bl_iw7027->spi, 0x40, val_0, 20); + } + + iw7027_spi_op_flag = 0; + return 0; +} + +static int iw7027_power_on(void) +{ + if (iw7027_on_flag) { + LDIMPR("%s: iw7027 is already on, exit\n", __func__); + return 0; + } + iw7027_hw_init_on(); + iw7027_on_flag = 1; + + LDIMPR("%s: ok\n", __func__); + return 0; +} + +static int iw7027_power_off(void) +{ + iw7027_on_flag = 0; + iw7027_hw_init_off(); + + LDIMPR("%s: ok\n", __func__); + return 0; +} + +static ssize_t iw7027_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + struct iw7027 *bl = container_of(class, struct iw7027, cls); + int ret = 0; + int i; + + if (!strcmp(attr->attr.name, "mode")) { + ret = sprintf(buf, "0x%02x\n", bl->spi->mode); + } else if (!strcmp(attr->attr.name, "speed")) { + ret = sprintf(buf, "%d\n", bl->spi->max_speed_hz); + } else if (!strcmp(attr->attr.name, "test")) { + ret = sprintf(buf, "test mode=%d\n", bl->test_mode); + } else if (!strcmp(attr->attr.name, "brightness")) { + ret = sprintf(buf, "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n", + test_brightness[0], + test_brightness[1], + test_brightness[2], + test_brightness[3], + test_brightness[4], + test_brightness[5], + test_brightness[6], + test_brightness[7]); + } else if (!strcmp(attr->attr.name, "status")) { + ret = sprintf(buf, "iw7027 status:\n" + "dev_index = %d\n" + "on_flag = %d\n" + "en_on = %d\n" + "en_off = %d\n" + "cs_hold_delay = %d\n" + "cs_clk_delay = %d\n" + "spi_op_flag = %d\n" + "dim_max = 0x%03x\n" + "dim_min = 0x%03x\n", + ldim_drv->dev_index, iw7027_on_flag, + ldim_drv->ldev_conf->en_gpio_on, + ldim_drv->ldev_conf->en_gpio_off, + ldim_drv->ldev_conf->cs_hold_delay, + ldim_drv->ldev_conf->cs_clk_delay, + iw7027_spi_op_flag, + ldim_drv->ldev_conf->dim_max, + ldim_drv->ldev_conf->dim_min); + } else if (!strcmp(attr->attr.name, "dump_low")) { + i = 1000; + while ((iw7027_spi_op_flag) && (i > 0)) { + i--; + udelay(10); + } + if (iw7027_spi_op_flag == 0) { + iw7027_spi_op_flag = 1; + ret = iw7027_spi_dump_low(buf); + iw7027_spi_op_flag = 0; + } else { + LDIMERR("%s: wait spi idle state failed\n", __func__); + } + ret += sprintf(buf, "\n"); + } else if (!strcmp(attr->attr.name, "dump_high")) { + i = 1000; + while ((iw7027_spi_op_flag) && (i > 0)) { + i--; + udelay(10); + } + if (iw7027_spi_op_flag == 0) { + iw7027_spi_op_flag = 1; + ret = iw7027_spi_dump_high(buf); + iw7027_spi_op_flag = 0; + } else { + LDIMERR("%s: wait spi idle state failed\n", __func__); + } + ret += sprintf(buf, "\n"); + } + + return ret; +} + +#define MAX_ARG_NUM 3 +static ssize_t iw7027_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + struct iw7027 *bl = container_of(class, struct iw7027, cls); + unsigned int val, val2; + unsigned char reg_addr, reg_val; + int i; + + if (!strcmp(attr->attr.name, "init")) { + iw7027_hw_init_on(); + } else if (!strcmp(attr->attr.name, "mode")) { + i = kstrtouint(buf, 10, &val); + if (i == 1) + bl->spi->mode = val; + else + LDIMERR("%s: invalid args\n", __func__); + } else if (!strcmp(attr->attr.name, "speed")) { + i = kstrtouint(buf, 10, &val); + if (i == 1) + bl->spi->max_speed_hz = val*1000; + else + LDIMERR("%s: invalid args\n", __func__); + } else if (!strcmp(attr->attr.name, "reg")) { + if (buf[0] == 'w') { + i = sscanf(buf, "w %x %x", &val, &val2); + if (i == 2) { + reg_addr = (unsigned char)val; + reg_val = (unsigned char)val2; + iw7027_wreg(bl->spi, reg_addr, reg_val); + } else { + LDIMERR("%s: invalid args\n", __func__); + } + } else if (buf[0] == 'r') { + i = sscanf(buf, "r %x", &val); + if (i == 1) { + reg_addr = (unsigned char)val; + iw7027_rreg(bl->spi, reg_addr, ®_val); + pr_info("reg 0x%02x = 0x%02x\n", + reg_addr, reg_val); + } else { + LDIMERR("%s: invalid args\n", __func__); + } + } + } else if (!strcmp(attr->attr.name, "test")) { + i = kstrtouint(buf, 10, &val); + LDIMPR("set test mode to %d\n", val); + bl->test_mode = val; + } else if (!strcmp(attr->attr.name, "brightness")) { + i = sscanf(buf, "%d %d", &val, &val2); + val &= 0xfff; + LDIMPR("brightness=%d, index=%d\n", val, val2); + if ((i == 2) && (val2 < ARRAY_SIZE(test_brightness))) + test_brightness[val2] = val; + } else + LDIMERR("LDIM argment error!\n"); + return count; +} + +static struct class_attribute iw7027_class_attrs[] = { + __ATTR(init, 0644, iw7027_show, iw7027_store), + __ATTR(mode, 0644, iw7027_show, iw7027_store), + __ATTR(speed, 0644, iw7027_show, iw7027_store), + __ATTR(reg, 0644, iw7027_show, iw7027_store), + __ATTR(test, 0644, iw7027_show, iw7027_store), + __ATTR(brightness, 0644, iw7027_show, iw7027_store), + __ATTR(status, 0644, iw7027_show, NULL), + __ATTR(dump_low, 0644, iw7027_show, NULL), + __ATTR(dump_high, 0644, iw7027_show, NULL), + __ATTR_NULL +}; + +static int iw7027_ldim_driver_update(void) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + + ldim_drv->device_power_on = iw7027_power_on; + ldim_drv->device_power_off = iw7027_power_off; + ldim_drv->device_bri_update = iw7027_smr; + return 0; +} + +static int ldim_spi_dev_probe(struct spi_device *spi) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + int ret; + + ldim_drv->spi = spi; + + dev_set_drvdata(&spi->dev, ldim_drv->ldev_conf); + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret) + LDIMERR("spi setup failed\n"); + + LDIMPR("%s ok\n", __func__); + return ret; +} + +static int ldim_spi_dev_remove(struct spi_device *spi) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + + ldim_drv->spi = NULL; + return 0; +} + +static struct spi_driver ldim_spi_dev_driver = { + .probe = ldim_spi_dev_probe, + .remove = ldim_spi_dev_remove, + .driver = { + .name = "ldim_dev", + .owner = THIS_MODULE, + }, +}; + +int ldim_dev_iw7027_probe(void) +{ + struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver(); + int ret; + + iw7027_on_flag = 0; + iw7027_spi_op_flag = 0; + + bl_iw7027 = kzalloc(sizeof(struct iw7027), GFP_KERNEL); + if (bl_iw7027 == NULL) { + LDIMERR("malloc bl_iw7027 failed\n"); + return -1; + } + + spi_register_board_info(ldim_drv->spi_dev, 1); + ret = spi_register_driver(&ldim_spi_dev_driver); + if (ret) { + LDIMERR("register ldim_dev spi driver failed\n"); + return -1; + } + + bl_iw7027->test_mode = 0; + bl_iw7027->spi = ldim_drv->spi; + bl_iw7027->cs_hold_delay = ldim_drv->ldev_conf->cs_hold_delay; + bl_iw7027->cs_clk_delay = ldim_drv->ldev_conf->cs_clk_delay; + bl_iw7027->cmd_size = ldim_drv->ldev_conf->cmd_size; + bl_iw7027->init_data = ldim_drv->ldev_conf->init_on; + + iw7027_ldim_driver_update(); + + bl_iw7027->cls.name = kzalloc(10, GFP_KERNEL); + sprintf((char *)bl_iw7027->cls.name, "iw7027"); + bl_iw7027->cls.class_attrs = iw7027_class_attrs; + ret = class_register(&bl_iw7027->cls); + if (ret < 0) + pr_err("register iw7027 class failed\n"); + + iw7027_on_flag = 1; /* default enable in uboot */ + + LDIMPR("%s ok\n", __func__); + return ret; +} + +int ldim_dev_iw7027_remove(void) +{ + spi_unregister_driver(&ldim_spi_dev_driver); + kfree(bl_iw7027); + bl_iw7027 = NULL; + + return 0; +} + diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h b/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h new file mode 100644 index 0000000..2d1b4c7 --- /dev/null +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h @@ -0,0 +1,115 @@ +/* + * drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h + * + * Copyright (C) 2017 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. + * + */ + +#ifndef __IW7027_HW_H +#define __IW7027_HW_H + +#define CHECK_INIT_DONE_MAX_COUNT 10 + +#define BRIGHTNESS_2D 0x7FF +#define BRIGHTNESS_3D 0x333 + +#define BRIGHTNESS_2D_MAX 0xFFF +#define BRIGHTNESS_3D_MAX 0x500 + +/* skyworht 39" */ +#define ISET_VALUE_2D_SKY39 0xB43C +#define ISET_VALUE_3D_SKY39 0xB4B4 +#define VDAC_VALUE_2D_SKY39 0xE5 +#define VDAC_VALUE_3D_SKY39 0x85 + +#define VDAC_MIN_2D_SKY39 0xB0 +#define VDAC_MAX_2D_SKY39 0xF1 +#define VDAC_MIN_3D_SKY39 0x00 +#define VDAC_MAX_3D_SKY39 0x96 + +/* skyworht 42" */ +#define ISET_VALUE_2D_SKY42 0xA537 +#define ISET_VALUE_3D_SKY42 0xA5A5 +#define VDAC_VALUE_2D_SKY42 0xE6 +#define VDAC_VALUE_3D_SKY42 0x84 + +#define VDAC_MIN_2D_SKY42 0xB3 +#define VDAC_MAX_2D_SKY42 0xF4 +#define VDAC_MIN_3D_SKY42 0x3A +#define VDAC_MAX_3D_SKY42 0x97 + +/* skyworht 50" */ +#define ISET_VALUE_2D_SKY50 0xB43C +#define ISET_VALUE_3D_SKY50 0xB4B4 +#define VDAC_VALUE_2D_SKY50 0xE1 +#define VDAC_VALUE_3D_SKY50 0x77 + +#define VDAC_MIN_2D_SKY50 0xC0 +#define VDAC_MAX_2D_SKY50 0xF5 +#define VDAC_MIN_3D_SKY50 0x47 +#define VDAC_MAX_3D_SKY50 0xA3 + +#define EEPROM_ADDR_VDAC_2D 3504 /* 0xDB0 */ +#define EEPROM_ADDR_VDAC_3D 3506 /* 0xDB2 */ + +#define VSYNC_CNT_2D_3D 64 +#define VSYNC_CNT_3D_2D 64 +#define VSYNC_CNT_SET_BRI_ZERO 49 +#define VSYNC_CNT_RAMP 45 +#define VSYNC_CNT_SET_BRI_2D 15 +#define VSYNC_CNT_SET_BRI_3D 15 +#define VSYNC_CNT_WAIT_EN_PROT 0 + +/* scan timing parameters for 42"*/ +#define DEFAULT_TD0_2D 333 /* 0.333ms */ +#define DEFAULT_DG1_2D 720 /* 0.720ms */ +#define DEFAULT_DELTAT_2D 790 /* 0.790ms */ + +#define DEFAULT_TD0_3D 333 /* 0.333ms */ +#define DEFAULT_DG1_3D 720 /* 0.720ms */ +#define DEFAULT_DELTAT_3D 790 /* 0.790ms */ + +/* scan timing parameters for 39"*/ +#define DEFAULT_TD0_2D_SKY39 333 /* 0.333ms */ +#define DEFAULT_DG1_2D_SKY39 700 /* 0.700ms */ +#define DEFAULT_DELTAT_2D_SKY39 1104 /* 1.104ms */ + +#define DEFAULT_TD0_3D_SKY39 333 /* 0.333ms */ +#define DEFAULT_DG1_3D_SKY39 700 /* 0.700ms */ +#define DEFAULT_DELTAT_3D_SKY39 1104 /* 1.104ms */ + +/* scan timing parameters for 50"*/ +#define DEFAULT_TD0_2D_SKY50 333 /* 0.333ms */ +#define DEFAULT_DG1_2D_SKY50 720 /* 0.720ms */ +#define DEFAULT_DELTAT_2D_SKY50 790 /* 1.120ms */ + +#define DEFAULT_TD0_3D_SKY50 333 /* 0.333ms */ +#define DEFAULT_DG1_3D_SKY50 720 /* 0.720ms */ +#define DEFAULT_DELTAT_3D_SKY50 790 /* 1.120ms */ + +#define EEPROM_ADDR_PANEL 3463 + +struct iwatt_reg_map { + u16 addr; + u16 val_2d; + u16 val_3d; +}; + +extern int dirspi_write(struct spi_device *spi, u8 *buf, int len); +extern int dirspi_read(struct spi_device *spi, u8 *buf, int len); +extern void dirspi_start(struct spi_device *spi); +extern void dirspi_stop(struct spi_device *spi); +#endif /* __IW7027_HW_H */ + + + diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c index ae6a3ad..ac9c056 100644 --- a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c @@ -81,18 +81,6 @@ struct ldim_dev_config_s ldim_dev_config = { }, }; -/* ****************************************************** */ -static char *ldim_pinmux_str[] = { - "PWM_A", /* 0 */ - "PWM_B", /* 1 */ - "PWM_C", /* 2 */ - "PWM_D", /* 3 */ - "PWM_E", /* 4 */ - "PWM_F", /* 5 */ - "PWM_VS", /* 6 */ - "none", -}; - #if 0 static void ldim_gpio_release(int index) { @@ -380,6 +368,13 @@ void ldim_set_duty_pwm(struct bl_pwm_config_s *ld_pwm) } } +/* ****************************************************** */ +static char *ldim_pinmux_str[] = { + "ldim_pwm", /* 0 */ + "ldim_pwm_vs", /* 1 */ + "none", +}; + /* set ldim pwm_vs */ static int ldim_pwm_pinmux_ctrl(char *pin_str) { @@ -396,14 +391,26 @@ static int ldim_pwm_pinmux_ctrl(char *pin_str) bl_pwm_ctrl(ld_pwm, 1); /* request pwm pinmux */ - ldim_drv->pin = devm_pinctrl_get_select(ldim_drv->dev, - ldim_pinmux_str[ld_pwm->pwm_port]); - if (IS_ERR(ldim_drv->pin)) { - BLERR("set %s pinmux error\n", - ldim_pinmux_str[ld_pwm->pwm_port]); + if (ld_pwm->pwm_port == BL_PWM_VS) { + ldim_drv->pin = devm_pinctrl_get_select(ldim_drv->dev, + ldim_pinmux_str[1]); + if (IS_ERR(ldim_drv->pin)) { + LDIMERR("set %s pinmux error\n", + ldim_pinmux_str[1]); + } else { + LDIMPR("request %s pinmux: %p\n", + ldim_pinmux_str[1], ldim_drv->pin); + } } else { - BLPR("request %s pinmux: %p\n", - ldim_pinmux_str[ld_pwm->pwm_port], ldim_drv->pin); + ldim_drv->pin = devm_pinctrl_get_select(ldim_drv->dev, + ldim_pinmux_str[0]); + if (IS_ERR(ldim_drv->pin)) { + LDIMERR("set %s pinmux error\n", + ldim_pinmux_str[0]); + } else { + LDIMPR("request %s pinmux: %p\n", + ldim_pinmux_str[0], ldim_drv->pin); + } } return ret; @@ -756,7 +763,10 @@ static int ldim_dev_add_driver(struct ldim_dev_config_s *ldev_conf, int index) { int ret = 0; - if (strcmp(ldev_conf->name, "ob3350") == 0) { + if (strcmp(ldev_conf->name, "iw7027") == 0) { + ret = ldim_dev_iw7027_probe(); + goto ldim_dev_add_driver_next; + } else if (strcmp(ldev_conf->name, "ob3350") == 0) { ret = ldim_dev_ob3350_probe(); goto ldim_dev_add_driver_next; } else if (strcmp(ldev_conf->name, "global") == 0) { @@ -783,7 +793,10 @@ static int ldim_dev_remove_driver(struct ldim_dev_config_s *ldev_conf, { int ret = 0; - if (strcmp(ldev_conf->name, "ob3350") == 0) { + if (strcmp(ldev_conf->name, "iw7027") == 0) { + ret = ldim_dev_iw7027_remove(); + goto ldim_dev_remove_driver_next; + } else if (strcmp(ldev_conf->name, "ob3350") == 0) { ret = ldim_dev_ob3350_remove(); goto ldim_dev_remove_driver_next; } else if (strcmp(ldev_conf->name, "global") == 0) { diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.h b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.h index db27a22..690969c 100644 --- a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.h +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.h @@ -21,6 +21,8 @@ extern void ldim_gpio_set(int index, int value); extern unsigned int ldim_gpio_get(int index); +extern int ldim_dev_iw7027_probe(void); +extern int ldim_dev_iw7027_remove(void); extern int ldim_dev_ob3350_probe(void); extern int ldim_dev_ob3350_remove(void); extern void ldim_set_duty_pwm(struct bl_pwm_config_s *ld_pwm); diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_drv.c b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_drv.c index c8d1f25..c9671c1 100644 --- a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_drv.c +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_drv.c @@ -81,7 +81,6 @@ static unsigned int incr_dif_gain = 16; static spinlock_t ldim_isr_lock; static spinlock_t rdma_ldim_isr_lock; -static struct tasklet_struct ldim_tasklet; static struct workqueue_struct *ldim_read_queue; static struct work_struct ldim_read_work; @@ -168,6 +167,7 @@ module_param(ldim_top_en, uint, 0664); MODULE_PARM_DESC(ldim_top_en, "ldim_top_en"); static struct aml_ldim_driver_s ldim_driver; +static void ldim_on_vs_spi(void); static void ldim_on_vs_arithmetic(void); static void ldim_update_setting(void); static void ldim_get_matrix_info_6(void); @@ -183,6 +183,7 @@ static void ldim_stts_read_region(struct work_struct *work) { ldim_read_region(ldim_hist_row, ldim_hist_col); ldim_on_vs_arithmetic(); + ldim_on_vs_spi(); } void LDIM_WR_32Bits(unsigned int addr, unsigned int data) @@ -1528,7 +1529,6 @@ static irqreturn_t ldim_vsync_isr(int irq, void *dev_id) default: break; } - tasklet_schedule(&ldim_tasklet); ldim_irq_cnt++; if (ldim_irq_cnt > 0xfffffff) @@ -1679,7 +1679,7 @@ static void ldim_update_matrix(unsigned int mode) LDIM_WR_32Bits(REG_LD_MISC_CTRL0, data); } -static void ldim_on_vs_spi(unsigned long data) +static void ldim_on_vs_spi(void) { unsigned int size; unsigned short *mapping; @@ -3023,7 +3023,6 @@ int aml_ldim_probe(struct platform_device *pdev) goto err3; } - tasklet_init(&ldim_tasklet, ldim_on_vs_spi, 123); ldim_read_queue = create_singlethread_workqueue("ldim read"); if (!ldim_read_queue) { LDIMERR("ldim_read_queue create failed\n"); @@ -3035,16 +3034,15 @@ int aml_ldim_probe(struct platform_device *pdev) spin_lock_init(&ldim_isr_lock); spin_lock_init(&rdma_ldim_isr_lock); - ldim_driver.res_ldim_irq = platform_get_resource(pdev, + bl_drv->res_ldim_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ldim_driver.res_ldim_irq) { + if (!bl_drv->res_ldim_irq) { ret = -ENODEV; goto err; } else { - ldim_irq = ldim_driver.res_ldim_irq->start; + ldim_irq = bl_drv->res_ldim_irq->start; LDIMPR("ldim_irq: %d\n", ldim_irq); - - if (request_irq(ldim_irq, ldim_vsync_isr, 0, + if (request_irq(ldim_irq, ldim_vsync_isr, IRQF_SHARED, "ldim_vsync", (void *)"ldim_vsync")) LDIMERR("can't request ldim_irq\n"); else @@ -3053,16 +3051,16 @@ int aml_ldim_probe(struct platform_device *pdev) switch (bl_drv->data->chip_type) { case BL_CHIP_GXTVBB: - ldim_driver.res_rdma_irq = platform_get_resource(pdev, + bl_drv->res_rdma_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!ldim_driver.res_rdma_irq) { + if (!bl_drv->res_rdma_irq) { ret = -ENODEV; goto err; } else { - rdma_irq = ldim_driver.res_rdma_irq->start; + rdma_irq = bl_drv->res_rdma_irq->start; LDIMPR("rdma_irq: %d\n", rdma_irq); - if (request_irq(rdma_irq, rdma_ldim_intr, 0, + if (request_irq(rdma_irq, rdma_ldim_intr, IRQF_SHARED, "rdma_ldim", (void *)"rdma_ldim")) LDIMERR("can't request rdma_ldim\n"); else @@ -3093,6 +3091,7 @@ err: int aml_ldim_remove(void) { unsigned int i; + struct aml_bl_drv_s *bl_drv = aml_bl_get_driver(); kfree(FDat.SF_BL_matrix); kfree(FDat.TF_BL_matrix); @@ -3105,9 +3104,8 @@ int aml_ldim_remove(void) kfree(ldim_driver.ldim_test_matrix); kfree(ldim_driver.local_ldim_matrix); - free_irq(ldim_driver.res_rdma_irq->start, (void *)"rdma_ldim"); - free_irq(ldim_driver.res_ldim_irq->start, (void *)"ldim_vsync"); - tasklet_kill(&ldim_tasklet); + free_irq(bl_drv->res_rdma_irq->start, (void *)"rdma_ldim"); + free_irq(bl_drv->res_ldim_irq->start, (void *)"ldim_vsync"); cdev_del(aml_ldim_cdevp); kfree(aml_ldim_cdevp); diff --git a/include/linux/amlogic/media/vout/lcd/aml_bl.h b/include/linux/amlogic/media/vout/lcd/aml_bl.h index cc5147d..e1ad8d8 100644 --- a/include/linux/amlogic/media/vout/lcd/aml_bl.h +++ b/include/linux/amlogic/media/vout/lcd/aml_bl.h @@ -180,6 +180,8 @@ struct aml_bl_drv_s { struct backlight_device *bldev; struct workqueue_struct *workqueue; struct delayed_work bl_delayed_work; + struct resource *res_ldim_irq; + struct resource *res_rdma_irq; }; extern struct aml_bl_drv_s *aml_bl_get_driver(void); diff --git a/include/linux/amlogic/media/vout/lcd/aml_ldim.h b/include/linux/amlogic/media/vout/lcd/aml_ldim.h index 99f5cf5..76c4403 100644 --- a/include/linux/amlogic/media/vout/lcd/aml_ldim.h +++ b/include/linux/amlogic/media/vout/lcd/aml_ldim.h @@ -82,8 +82,6 @@ struct aml_ldim_driver_s { struct device *dev; struct spi_device *spi; struct spi_board_info *spi_dev; - struct resource *res_ldim_irq; - struct resource *res_rdma_irq; }; extern struct aml_ldim_driver_s *aml_ldim_get_driver(void); -- 2.7.4