ldim: add iw7027 driver
authorWeiming Liu <weiming.liu@amlogic.com>
Thu, 19 Apr 2018 02:16:52 +0000 (10:16 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Fri, 27 Apr 2018 12:42:35 +0000 (05:42 -0700)
PD#164701: ldim: add iw7027 driver

Change-Id: I75dd8e802b2eecf2d3d9d2f32935721f1a1bb285
Signed-off-by: Weiming Liu <weiming.liu@amlogic.com>
MAINTAINERS
arch/arm64/boot/dts/amlogic/mesontxlx_r311-panel.dtsi
drivers/amlogic/media/vout/backlight/aml_ldim/Makefile
drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c [new file with mode: 0644]
drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h [new file with mode: 0644]
drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c
drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.h
drivers/amlogic/media/vout/backlight/aml_ldim/ldim_drv.c
include/linux/amlogic/media/vout/lcd/aml_bl.h
include/linux/amlogic/media/vout/lcd/aml_ldim.h

index baa1cdd..807f5aa 100644 (file)
@@ -14427,3 +14427,9 @@ AMLOGIC LCD ADD TVCONFIG SUPPORT
 M:     Evoke Zhang <evoke.zhang@amlogic.com>
 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 <weiming.liu@amlogic.com>
+F:     drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c
+F:     drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.h
+
index e99988a..b0308c2 100644 (file)
                        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{
                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
                        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 / */
index 2830aa8..5da4662 100644 (file)
@@ -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 (file)
index 0000000..e6cac94
--- /dev/null
@@ -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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/amlogic/media/vout/lcd/aml_ldim.h>
+#include <linux/amlogic/media/vout/lcd/aml_bl.h>
+#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, &reg_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, &reg_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, &reg_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 (file)
index 0000000..2d1b4c7
--- /dev/null
@@ -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 */
+
+
+
index ae6a3ad..ac9c056 100644 (file)
@@ -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) {
index db27a22..690969c 100644 (file)
@@ -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);
index c8d1f25..c9671c1 100644 (file)
@@ -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);
index cc5147d..e1ad8d8 100644 (file)
@@ -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);
index 99f5cf5..76c4403 100644 (file)
@@ -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);