backlight: ldim: add analog pwm support [1/1]

PD#SWPL-3702

Problem:
local dimming need analog pwm function

Solution:
add analog pwm support

Verify:
x301

Change-Id: I502bb7505947c1f3670f44d0d307f9546f1d57fd
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>

Conflicts:
	arch/arm/boot/dts/amlogic/mesontl1_t309-panel.dtsi
	arch/arm/boot/dts/amlogic/mesontl1_x301-panel.dtsi
	arch/arm/boot/dts/amlogic/mesontxlx_r311-panel.dtsi
	arch/arm64/boot/dts/amlogic/mesontl1_t309-panel.dtsi
	arch/arm64/boot/dts/amlogic/mesontl1_x301-panel.dtsi
	drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c
	drivers/amlogic/media/vout/backlight/aml_ldim/ldim_drv.h
	include/linux/amlogic/media/vout/lcd/aml_ldim.h
This commit is contained in:
Evoke Zhang
2019-01-03 06:40:26 -05:00
committed by Dongjin Kim
parent 2f1f394941
commit 199e697b7f
11 changed files with 497 additions and 171 deletions

View File

@@ -653,6 +653,64 @@
2 0 /*pwm1 gpio_index, gpio_off*/
10 10>; /*pwm_on_delay(ms), pwm_off_delay(ms)*/
};
backlight_3{
index = <3>;
bl_name = "pwm_combo_ldim_test";
bl_level_default_uboot_kernel = <31 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <2>; /*1=pwm,2=pwm_combo,3=ldim*/
bl_power_attr = <0 /*en_gpio_index*/
1 0 /*on_value, off_value*/
410 110>; /*on_delay(ms), off_delay(ms)*/
bl_pwm_combo_level_mapping = <255 10 /*pwm_0 range*/
0 0>; /*pwm_1 range*/
bl_pwm_combo_port = "PWM_C","PWM_D";
bl_pwm_combo_attr = <1 /*pwm0 method*/
180 /*pwm0 freq(pwm:Hz, pwm_vs:multiple of vs)*/
100 25 /*pwm0 duty_max(%), duty_min(%)*/
1 /*pwm1 method*/
18000 /*pwm1 freq(pwm:Hz, pwm_vs:multi of vs)*/
80 80>; /*pwm1 duty_max(%), duty_min(%)*/
bl_pwm_combo_power = <1 0 /*pwm0 gpio_index, gpio_off*/
2 0 /*pwm1 gpio_index, gpio_off*/
10 10>; /*pwm_on_delay(ms), pwm_off_delay(ms)*/
bl_ldim_region_row_col = <2 10>;
};
backlight_4{
index = <4>;
bl_name = "ldim_global";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <3>; /*1=pwm,2=pwm_combo,3=ldim*/
bl_power_attr = <0xff /*en_gpio_index*/
1 0 /*on_value, off_value*/
200 200>; /*on_delay(ms), off_delay(ms)*/
bl_ldim_region_row_col = <1 1>;
bl_ldim_mode = <1>; /*0=left/right side
*1=top/bottom side
*2=direct
*/
ldim_dev_index = <1>;
};
backlight_5{
index = <5>;
bl_name = "ldim_iw7027";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <3>; /*1=pwm,2=pwm_combo,3=ldim*/
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 10>;
bl_ldim_mode = <1>; /*0=left/right side
*1=top/bottom side
*2=direct
*/
ldim_dev_index = <2>;
};
};
bl_pwm_conf:bl_pwm_conf{
@@ -666,4 +724,111 @@
};
};
local_dimming_device {
compatible = "amlogic, ldim_dev";
status = "okay";
pinctrl-names = "ldim_pwm",
"ldim_pwm_vs",
"ldim_pwm_combo",
"ldim_pwm_vs_combo",
"ldim_pwm_off",
"ldim_pwm_combo_off";
pinctrl-0 = <&pwm_c_pins3>;
pinctrl-1 = <&bl_pwm_vs_on_pins>;
pinctrl-2 = <&pwm_c_pins3 &pwm_d_pins2>;
pinctrl-3 = <&bl_pwm_vs_on_pins &pwm_d_pins2>;
pinctrl-4 = <&bl_pwm_off_pins>;
pinctrl-5 = <&bl_pwm_combo_off_pins>;
pinctrl_version = <1>; /* for uboot */
ldim_pwm_config = <&bl_pwm_conf>;
/* pwm port: PWM_A, PWM_B, PWM_C, PWM_D, PWM_E, PWM_F, PWM_VS*/
ldim_dev-gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH
&gpio GPIOZ_5 GPIO_ACTIVE_HIGH
&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>;
ldim_dev_gpio_names = "GPIOAO_11","GPIOZ_5","GPIOZ_6";
ldim_dev_0 {
index = <0>;
type = <0>; /*0=normal, 1=spi, 2=i2c*/
ldim_dev_name = "ob3350";
ldim_pwm_port = "PWM_C";
ldim_pwm_attr = <0 /* pol */
200 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*default duty(%)*/
en_gpio_on_off = <0 /*ldim_dev-gpios index*/
1 0>; /*on_level, off_level*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
};
ldim_dev_1 {
index = <1>;
type = <0>; /*0=normal, 1=spi, 2=i2c*/
ldim_dev_name = "global";
ldim_pwm_port = "PWM_C";
ldim_pwm_attr = <1 /* pol */
180 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*default duty(%)*/
analog_pwm_port = "PWM_D";
analog_pwm_attr = <1 /*pol(0=negative, 1=positvie)*/
18000 /*freq(pwm:Hz)*/
100 25 /*duty_max(%), duty_min(%)*/
80>; /*default duty(%)*/
en_gpio_on_off = <0 /*ldim_dev-gpios index*/
1 0>; /*on_level, off_level*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
};
ldim_dev_2 {
index = <2>;
type = <1>; /* 0=normal,1=spi,2=i2c */
ldim_dev_name = "iw7027";
ldim_pwm_port = "PWM_VS";
ldim_pwm_attr = <1 /* pol */
2 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*default duty(%)*/
spi_bus_num = <0>;
spi_chip_select = <0>;
spi_max_frequency = <1000000>; /* 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 */
ldim_region_mapping = <0 1 2 3 4 5 6 7 8 9>;
cmd_size = <0xff>;
/* init: (type, data...) */
/* type: 0x00=cmd with delay,
* 0xc0=cmd,
* 0xfd=delay,
* 0xff=ending
*/
/* data: spi data, fill 0x0 for no use */
/* delay: unit ms */
init_on = <
0xc0 2 0x23 0x03
0xc0 2 0x24 0xff
0xc0 2 0x25 0x00
0xc0 2 0x26 0x00
0xc0 2 0x27 0x60
0xc0 2 0x29 0x00
0xc0 2 0x2a 0x00
0xc0 2 0x2b 0x00
0xc0 2 0x2c 0x73
0xc0 2 0x2d 0x37
0xc0 2 0x31 0x93
0xc0 2 0x32 0x0f
0xc0 2 0x33 0xff
0xc0 2 0x34 0xc8
0xc0 2 0x35 0xbf
0xff 0>;
init_off = <0xff 0>;
};
};
}; /* end of / */

View File

@@ -678,6 +678,23 @@
};
backlight_4{
index = <4>;
bl_name = "ldim_global";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <3>; /*1=pwm,2=pwm_combo,3=ldim*/
bl_power_attr = <0xff /*en_gpio_index*/
1 0 /*on_value, off_value*/
200 200>; /* on_delay(ms), off_delay(ms)*/
bl_ldim_region_row_col = <1 1>;
bl_ldim_mode = <1>; /*0=left/right side
*1=top/bottom side
*2=direct
*/
ldim_dev_index = <1>;
};
backlight_5{
index = <5>;
bl_name = "ldim_iw7027";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
@@ -687,29 +704,12 @@
1 0 /*on_value, off_value*/
200 200>; /*on_delay(ms), off_delay(ms)*/
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_mode = <1>; /*0=left/right side
*1=top/bottom side
*2=direct
*/
ldim_dev_index = <2>;
};
backlight_5{
index = <5>;
bl_name = "ldim_global";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <3>; /*1=pwm,2=pwm_combo,3=ldim*/
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 1>;
bl_ldim_mode = <1>; /*1=single_side
* (top, bottom, left or right),
*2=uniform(top/bottom, left/right)
*/
ldim_dev_index = <1>;
};
};
bl_pwm_conf:bl_pwm_conf{
@@ -728,54 +728,63 @@
status = "okay";
pinctrl-names = "ldim_pwm",
"ldim_pwm_vs",
"ldim_pwm_off";
"ldim_pwm_combo",
"ldim_pwm_vs_combo",
"ldim_pwm_off",
"ldim_pwm_combo_off";
pinctrl-0 = <&bl_pwm_on_pins>;
pinctrl-1 = <&bl_pwm_vs_on_pins>;
pinctrl-2 = <&bl_pwm_off_pins>;
pinctrl-2 = <&bl_pwm_on_pins &bl_pwm_combo_1_on_pins>;
pinctrl-3 = <&bl_pwm_vs_on_pins &bl_pwm_combo_1_on_pins>;
pinctrl-4 = <&bl_pwm_off_pins>;
pinctrl-5 = <&bl_pwm_combo_off_pins>;
pinctrl_version = <1>; /* for uboot */
ldim_pwm_config = <&bl_pwm_conf>;
/* pwm port: PWM_A, PWM_B, PWM_C, PWM_D, PWM_E, PWM_F, PWM_VS*/
ldim_dev-gpios = <&gpio GPIOZ_12 GPIO_ACTIVE_HIGH
&gpio GPIOZ_6 GPIO_ACTIVE_HIGH
&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>;
ldim_dev_gpio_names = "GPIOZ_12","GPIOZ_6","GPIOZ_7";
&gpio GPIOZ_7 GPIO_ACTIVE_HIGH
&gpio GPIOZ_4 GPIO_ACTIVE_HIGH>;
ldim_dev_gpio_names = "GPIOZ_12","GPIOZ_6","GPIOZ_7","GPIOZ_4";
ldim_dev_0 {
index = <0>;
type = <0>; /*0=normal, 1=spi, 2=i2c*/
ldim_dev_name = "ob3350";
ldim_pwm_pinmux_sel = "ldim_pwm";
ldim_pwm_port = "PWM_B";
ldim_pwm_attr = <0 /* pol */
200 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*duty(%)*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
50>;/*default duty(%)*/
en_gpio_on_off = <0 /*ldim_dev-gpios index*/
1 0>; /*on_level, off_level*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
};
ldim_dev_1 {
index = <1>;
type = <0>; /*0=normal, 1=spi, 2=i2c*/
ldim_dev_name = "global";
ldim_pwm_pinmux_sel = "ldim_pwm";
ldim_pwm_port = "PWM_B";
ldim_pwm_attr = <1 /* pol */
180 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*duty(%)*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
en_gpio_on_off = <2 /*ldim_dev-gpios index*/
50>;/*default duty(%)*/
analog_pwm_port = "PWM_C";
analog_pwm_attr = <1 /*pol(0=negative, 1=positvie)*/
18000 /*freq(pwm:Hz)*/
100 25 /*duty_max(%), duty_min(%)*/
80>; /*default duty(%)*/
en_gpio_on_off = <3 /*ldim_dev-gpios index*/
1 0>; /*on_level, off_level*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
};
ldim_dev_2 {
index = <2>;
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(%)*/
50>;/*default duty(%)*/
spi_bus_num = <0>;
spi_chip_select = <0>;
spi_max_frequency = <1000000>; /* unit: hz */

View File

@@ -39,6 +39,8 @@
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c_AO;
spi0 = &spicc0;
spi1 = &spicc1;
};
memory@00000000 {

View File

@@ -678,6 +678,23 @@
};
backlight_4{
index = <4>;
bl_name = "ldim_global";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <3>; /*1=pwm,2=pwm_combo,3=ldim*/
bl_power_attr = <0xff /*en_gpio_index*/
1 0 /*on_value, off_value*/
200 200>; /* on_delay(ms), off_delay(ms)*/
bl_ldim_region_row_col = <1 1>;
bl_ldim_mode = <1>; /*0=left/right side
*1=top/bottom side
*2=direct
*/
ldim_dev_index = <1>;
};
backlight_5{
index = <5>;
bl_name = "ldim_iw7027";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
@@ -693,23 +710,6 @@
*/
ldim_dev_index = <2>;
};
backlight_5{
index = <5>;
bl_name = "ldim_global";
bl_level_default_uboot_kernel = <100 100>;
bl_level_attr = <255 10 /*max, min*/
128 128>; /*mid, mid_mapping*/
bl_ctrl_method = <3>; /*1=pwm,2=pwm_combo,3=ldim*/
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 1>;
bl_ldim_mode = <1>; /*0=left/right side
*1=top/bottom side
*2=direct
*/
ldim_dev_index = <1>;
};
};
bl_pwm_conf:bl_pwm_conf{
@@ -728,54 +728,63 @@
status = "okay";
pinctrl-names = "ldim_pwm",
"ldim_pwm_vs",
"ldim_pwm_off";
"ldim_pwm_combo",
"ldim_pwm_vs_combo",
"ldim_pwm_off",
"ldim_pwm_combo_off";
pinctrl-0 = <&bl_pwm_on_pins>;
pinctrl-1 = <&bl_pwm_vs_on_pins>;
pinctrl-2 = <&bl_pwm_off_pins>;
pinctrl-2 = <&bl_pwm_on_pins &bl_pwm_combo_1_on_pins>;
pinctrl-3 = <&bl_pwm_vs_on_pins &bl_pwm_combo_1_on_pins>;
pinctrl-4 = <&bl_pwm_off_pins>;
pinctrl-5 = <&bl_pwm_combo_off_pins>;
pinctrl_version = <1>; /* for uboot */
ldim_pwm_config = <&bl_pwm_conf>;
/* pwm port: PWM_A, PWM_B, PWM_C, PWM_D, PWM_E, PWM_F, PWM_VS*/
ldim_dev-gpios = <&gpio GPIOZ_12 GPIO_ACTIVE_HIGH
&gpio GPIOZ_6 GPIO_ACTIVE_HIGH
&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>;
ldim_dev_gpio_names = "GPIOZ_12","GPIOZ_6","GPIOZ_7";
&gpio GPIOZ_7 GPIO_ACTIVE_HIGH
&gpio GPIOZ_4 GPIO_ACTIVE_HIGH>;
ldim_dev_gpio_names = "GPIOZ_12","GPIOZ_6","GPIOZ_7","GPIOZ_4";
ldim_dev_0 {
index = <0>;
type = <0>; /*0=normal, 1=spi, 2=i2c*/
ldim_dev_name = "ob3350";
ldim_pwm_pinmux_sel = "ldim_pwm";
ldim_pwm_port = "PWM_B";
ldim_pwm_attr = <0 /* pol */
200 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*duty(%)*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
50>;/*default duty(%)*/
en_gpio_on_off = <0 /*ldim_dev-gpios index*/
1 0>; /*on_level, off_level*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
};
ldim_dev_1 {
index = <1>;
type = <0>; /*0=normal, 1=spi, 2=i2c*/
ldim_dev_name = "global";
ldim_pwm_pinmux_sel = "ldim_pwm";
ldim_pwm_port = "PWM_B";
ldim_pwm_attr = <1 /* pol */
180 /*freq(pwm:Hz, pwm_vs:multiple of vs)*/
50>;/*duty(%)*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
en_gpio_on_off = <2 /*ldim_dev-gpios index*/
50>;/*default duty(%)*/
analog_pwm_port = "PWM_C";
analog_pwm_attr = <1 /*pol(0=negative, 1=positvie)*/
18000 /*freq(pwm:Hz)*/
100 25 /*duty_max(%), duty_min(%)*/
80>; /*default duty(%)*/
en_gpio_on_off = <3 /*ldim_dev-gpios index*/
1 0>; /*on_level, off_level*/
dim_max_min = <100 20>; /*dim_max, dim_min*/
};
ldim_dev_2 {
index = <2>;
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(%)*/
50>;/*default duty(%)*/
spi_bus_num = <0>;
spi_chip_select = <0>;
spi_max_frequency = <1000000>; /* unit: hz */
@@ -818,6 +827,7 @@
0xc0 2 0x34 0xc8
0xc0 2 0x35 0xbf
0xff 0>;
init_off = <0xff 0>;
};
};

View File

@@ -330,15 +330,6 @@ static void bl_gpio_set(int index, int value)
}
}
static inline unsigned int bl_do_div(unsigned long long num, unsigned int den)
{
unsigned long long ret = num;
do_div(ret, den);
return (unsigned int)ret;
}
/* ****************************************************** */
#define BL_PINMUX_MAX 8
static char *bl_pinmux_str[BL_PINMUX_MAX] = {
@@ -2865,11 +2856,11 @@ static ssize_t bl_debug_pwm_show(struct class *class,
return len;
}
#define BL_DEBUG_PWM_FREQ 0
#define BL_DEBUG_PWM_DUTY 1
#define BL_DEBUG_PWM_POL 2
#define BL_DEBUG_PWM_DUTY_MAX 3
#define BL_DEBUG_PWM_DUTY_MIN 4
#define BL_DEBUG_PWM_FREQ 0
#define BL_DEBUG_PWM_DUTY 1
#define BL_DEBUG_PWM_POL 2
#define BL_DEBUG_PWM_DUTY_MAX 3
#define BL_DEBUG_PWM_DUTY_MIN 4
static void bl_debug_pwm_set(unsigned int index, unsigned int value, int state)
{
struct bl_config_s *bconf = bl_drv->bconf;

View File

@@ -44,7 +44,8 @@ static int global_hw_init_on(void)
{
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->pwm_config));
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->ldim_pwm_config));
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->analog_pwm_config));
ldim_drv->pinmux_ctrl(1);
mdelay(2);
ldim_gpio_set(ldim_drv->ldev_conf->en_gpio,
@@ -61,7 +62,8 @@ static int global_hw_init_off(void)
ldim_gpio_set(ldim_drv->ldev_conf->en_gpio,
ldim_drv->ldev_conf->en_gpio_off);
ldim_drv->pinmux_ctrl(0);
ldim_pwm_off(&(ldim_drv->ldev_conf->pwm_config));
ldim_pwm_off(&(ldim_drv->ldev_conf->ldim_pwm_config));
ldim_pwm_off(&(ldim_drv->ldev_conf->analog_pwm_config));
return 0;
}
@@ -88,12 +90,22 @@ static int global_smr(unsigned short *buf, unsigned char len)
level = buf[0];
val = dim_min + ((level * (dim_max - dim_min)) / LD_DATA_MAX);
ldim_drv->ldev_conf->pwm_config.pwm_duty = val;
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->pwm_config));
ldim_drv->ldev_conf->ldim_pwm_config.pwm_duty = val;
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->ldim_pwm_config));
return 0;
}
static void global_dim_range_update(void)
{
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
struct ldim_dev_config_s *ldim_dev;
ldim_dev = ldim_drv->ldev_conf;
ldim_dev->dim_max = ldim_dev->ldim_pwm_config.pwm_duty_max;
ldim_dev->dim_min = ldim_dev->ldim_pwm_config.pwm_duty_min;
}
static int global_power_on(void)
{
if (global_on_flag) {
@@ -137,7 +149,7 @@ static ssize_t global_show(struct class *class,
ldim_drv->ldev_conf->en_gpio_off,
ldim_drv->ldev_conf->dim_max,
ldim_drv->ldev_conf->dim_min,
ldim_drv->ldev_conf->pwm_config.pwm_duty);
ldim_drv->ldev_conf->ldim_pwm_config.pwm_duty);
}
return ret;
@@ -150,6 +162,12 @@ static struct class_attribute global_class_attrs[] = {
static int global_ldim_driver_update(struct aml_ldim_driver_s *ldim_drv)
{
struct ldim_dev_config_s *ldim_dev = ldim_drv->ldev_conf;
ldim_dev->ldim_pwm_config.pwm_duty_max = ldim_dev->dim_max;
ldim_dev->ldim_pwm_config.pwm_duty_min = ldim_dev->dim_min;
ldim_dev->dim_range_update = global_dim_range_update;
ldim_drv->device_power_on = global_power_on;
ldim_drv->device_power_off = global_power_off;
ldim_drv->device_bri_update = global_smr;

View File

@@ -304,7 +304,8 @@ static int iw7027_hw_init_on(void)
iw7027_power_on_init();
/* step 5: supply stable vsync */
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->pwm_config));
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->ldim_pwm_config));
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->analog_pwm_config));
ldim_drv->pinmux_ctrl(1);
/* step 6: delay for system clock and light bar PSU stable */
@@ -336,7 +337,8 @@ static int iw7027_hw_init_off(void)
ldim_gpio_set(ldim_drv->ldev_conf->en_gpio,
ldim_drv->ldev_conf->en_gpio_off);
ldim_drv->pinmux_ctrl(0);
ldim_pwm_off(&(ldim_drv->ldev_conf->pwm_config));
ldim_pwm_off(&(ldim_drv->ldev_conf->ldim_pwm_config));
ldim_pwm_off(&(ldim_drv->ldev_conf->analog_pwm_config));
return 0;
}
@@ -648,7 +650,7 @@ static ssize_t iw7027_store(struct class *class,
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
struct iw7027_s *bl = container_of(class, struct iw7027_s, cls);
unsigned int val, val2;
unsigned char reg_addr, reg_val;
unsigned char reg_addr, reg_val, temp;
int i;
if (!strcmp(attr->attr.name, "init")) {
@@ -663,6 +665,10 @@ static ssize_t iw7027_store(struct class *class,
reg_addr = (unsigned char)val;
reg_val = (unsigned char)val2;
iw7027_wreg(bl->spi, reg_addr, reg_val);
iw7027_rreg(bl->spi, reg_addr, &temp);
pr_info(
"reg 0x%02x = 0x%02x, readback 0x%02x\n",
reg_addr, reg_val, temp);
mutex_unlock(&iw7027_spi_mutex);
} else {
LDIMERR("%s: invalid args\n", __func__);

View File

@@ -58,6 +58,7 @@ static struct spi_board_info ldim_spi_info = {
static unsigned char *table_init_on_dft;
static unsigned char *table_init_off_dft;
static int ldim_dev_probe_flag;
static struct class ldim_dev_class;
struct ldim_dev_config_s ldim_dev_config = {
.type = LDIM_DEV_TYPE_NORMAL,
@@ -77,11 +78,11 @@ struct ldim_dev_config_s ldim_dev_config = {
.init_off = NULL,
.init_on_cnt = 0,
.init_off_cnt = 0,
.pwm_config = {
.ldim_pwm_config = {
.pwm_method = BL_PWM_POSITIVE,
.pwm_port = BL_PWM_MAX,
.pwm_duty_max = 100,
.pwm_duty_min = 1,
.pwm_duty_min = 0,
},
.analog_pwm_config = {
.pwm_method = BL_PWM_POSITIVE,
@@ -257,14 +258,13 @@ unsigned int ldim_gpio_get(int index)
void ldim_set_duty_pwm(struct bl_pwm_config_s *bl_pwm)
{
unsigned long temp;
unsigned long long temp;
if (bl_pwm->pwm_port >= BL_PWM_MAX)
return;
temp = bl_pwm->pwm_cnt;
temp = (((temp * bl_pwm->pwm_duty) + 50) / 100);
bl_pwm->pwm_level = (unsigned int)temp;
bl_pwm->pwm_level = bl_do_div(((temp * bl_pwm->pwm_duty) + 50), 100);
if (ldim_debug_print == 2) {
LDIMPR(
@@ -288,42 +288,53 @@ void ldim_pwm_off(struct bl_pwm_config_s *bl_pwm)
static char *ldim_pinmux_str[] = {
"ldim_pwm", /* 0 */
"ldim_pwm_vs", /* 1 */
"ldim_pwm_off", /* 1 */
"none",
"ldim_pwm_combo", /* 2 */
"ldim_pwm_vs_combo", /* 3 */
"ldim_pwm_off", /* 4 */
"ldim_pwm_combo_off", /* 5 */
"custome",
};
static int ldim_pwm_pinmux_ctrl(int status)
{
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
struct bl_pwm_config_s *bl_pwm;
char *str;
int ret = 0, index = 0xff;
if (strcmp(ldim_drv->ldev_conf->pinmux_name, "invalid") == 0)
if (ldim_drv->ldev_conf->ldim_pwm_config.pwm_port >= BL_PWM_MAX)
return 0;
bl_pwm = &ldim_drv->ldev_conf->pwm_config;
if (bl_pwm->pwm_port >= BL_PWM_MAX)
return 0;
if (bl_pwm->pwm_port == BL_PWM_VS)
index = (status) ? 1 : 2;
else
index = (status) ? 0 : 2;
if (status) {
bl_pwm = &ldim_drv->ldev_conf->ldim_pwm_config;
if (bl_pwm->pwm_port == BL_PWM_VS)
index = 1;
else
index = 0;
bl_pwm = &ldim_drv->ldev_conf->analog_pwm_config;
if (bl_pwm->pwm_port < BL_PWM_VS)
index += 2;
} else {
bl_pwm = &ldim_drv->ldev_conf->analog_pwm_config;
if (bl_pwm->pwm_port < BL_PWM_VS)
index = 5;
else
index = 4;
}
str = ldim_pinmux_str[index];
if (ldim_drv->pinmux_flag == index) {
LDIMPR("pinmux %s is already selected\n",
ldim_pinmux_str[index]);
LDIMPR("pinmux %s is already selected\n", str);
return 0;
}
/* request pwm pinmux */
ldim_drv->pin = devm_pinctrl_get_select(ldim_drv->dev,
ldim_pinmux_str[index]);
ldim_drv->pin = devm_pinctrl_get_select(ldim_drv->dev, str);
if (IS_ERR(ldim_drv->pin)) {
LDIMERR("set pinmux %s error\n", ldim_pinmux_str[index]);
LDIMERR("set pinmux %s error\n", str);
ret = -1;
} else {
LDIMPR("set pinmux %s: 0x%p\n",
ldim_pinmux_str[index], ldim_drv->pin);
LDIMPR("set pinmux %s: 0x%p\n", str, ldim_drv->pin);
}
ldim_drv->pinmux_flag = index;
@@ -332,7 +343,7 @@ static int ldim_pwm_pinmux_ctrl(int status)
static int ldim_pwm_vs_update(void)
{
struct bl_pwm_config_s *bl_pwm = &ldim_dev_config.pwm_config;
struct bl_pwm_config_s *bl_pwm = &ldim_dev_config.ldim_pwm_config;
unsigned int cnt;
int ret = 0;
@@ -374,6 +385,10 @@ static void ldim_dev_init_table_dynamic_size_print(
table = econf->init_off;
max_len = econf->init_off_cnt;
}
if (max_len == 0) {
kfree(str);
return;
}
if (table == NULL) {
LDIMERR("init_table %d is NULL\n", flag);
kfree(str);
@@ -451,6 +466,10 @@ static void ldim_dev_init_table_fixed_size_print(
table = econf->init_off;
max_len = econf->init_off_cnt;
}
if (max_len == 0) {
kfree(str);
return;
}
if (table == NULL) {
LDIMERR("init_table %d is NULL\n", flag);
kfree(str);
@@ -487,7 +506,7 @@ static void ldim_dev_config_print(void)
pr_info("valid_flag = %d\n"
"dev_index = %d\n"
"vsync_change_flag = %d\n",
"vsync_change_flag = %d\n\n",
ldim_drv->valid_flag,
ldim_drv->dev_index,
ldim_drv->vsync_change_flag);
@@ -496,7 +515,6 @@ static void ldim_dev_config_print(void)
return;
}
bl_pwm = &ldim_drv->ldev_conf->pwm_config;
pr_info("dev_name = %s\n"
"type = %d\n"
"en_gpio = %d\n"
@@ -559,13 +577,14 @@ static void ldim_dev_config_print(void)
default:
break;
}
bl_pwm = &ldim_drv->ldev_conf->ldim_pwm_config;
if (bl_pwm->pwm_port < BL_PWM_MAX) {
pr_info("pwm_port: %d\n"
"pwm_pol: %d\n"
"pwm_freq: %d\n"
"pwm_cnt: %d\n"
"pwm_level: %d\n"
"pwm_duty: %d%%\n",
pr_info("lidm_pwm_port: %d\n"
"lidm_pwm_pol: %d\n"
"lidm_pwm_freq: %d\n"
"lidm_pwm_cnt: %d\n"
"lidm_pwm_level: %d\n"
"lidm_pwm_duty: %d%%\n",
bl_pwm->pwm_port, bl_pwm->pwm_method,
bl_pwm->pwm_freq, bl_pwm->pwm_cnt,
bl_pwm->pwm_level, bl_pwm->pwm_duty);
@@ -577,28 +596,28 @@ static void ldim_dev_config_print(void)
case BL_PWM_E:
case BL_PWM_F:
if (IS_ERR_OR_NULL(bl_pwm->pwm_data.pwm)) {
pr_info("pwm invalid\n");
pr_info("lidm_pwm invalid\n");
break;
}
pr_info("pwm_pointer: %p\n",
pr_info("lidm_pwm_pointer: 0x%p\n",
bl_pwm->pwm_data.pwm);
pwm_get_state(bl_pwm->pwm_data.pwm, &pstate);
pr_info("pwm state:\n"
" period: %d\n"
" duty_cycle: %d\n"
" polarity: %d\n"
" enabled: %d\n",
pr_info("lidm_pwm state:\n"
" period: %d\n"
" duty_cycle: %d\n"
" polarity: %d\n"
" enabled: %d\n",
pstate.period, pstate.duty_cycle,
pstate.polarity, pstate.enabled);
value = bl_cbus_read(
bl_drv->data->pwm_reg[bl_pwm->pwm_port]);
pr_info("pwm_reg: 0x%08x\n", value);
pr_info("lidm_pwm_reg: 0x%08x\n", value);
break;
case BL_PWM_VS:
pr_info("pwm_reg0: 0x%08x\n"
"pwm_reg1: 0x%08x\n"
"pwm_reg2: 0x%08x\n"
"pwm_reg3: 0x%08x\n",
pr_info("lidm_pwm_reg0: 0x%08x\n"
"lidm_pwm_reg1: 0x%08x\n"
"lidm_pwm_reg2: 0x%08x\n"
"lidm_pwm_reg3: 0x%08x\n",
bl_vcbus_read(VPU_VPU_PWM_V0),
bl_vcbus_read(VPU_VPU_PWM_V1),
bl_vcbus_read(VPU_VPU_PWM_V2),
@@ -608,16 +627,59 @@ static void ldim_dev_config_print(void)
break;
}
}
pr_info("pinmux_flag: %d\n"
"pinmux_pointer: 0x%p\n\n",
bl_pwm = &ldim_drv->ldev_conf->analog_pwm_config;
if (bl_pwm->pwm_port < BL_PWM_MAX) {
pr_info("\nanalog_pwm_port: %d\n"
"analog_pwm_pol: %d\n"
"analog_pwm_freq: %d\n"
"analog_pwm_cnt: %d\n"
"analog_pwm_level: %d\n"
"analog_pwm_duty: %d%%\n"
"analog_pwm_duty_max: %d%%\n"
"analog_pwm_duty_min: %d%%\n",
bl_pwm->pwm_port, bl_pwm->pwm_method,
bl_pwm->pwm_freq, bl_pwm->pwm_cnt,
bl_pwm->pwm_level, bl_pwm->pwm_duty,
bl_pwm->pwm_duty_max, bl_pwm->pwm_duty_min);
switch (bl_pwm->pwm_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:
if (IS_ERR_OR_NULL(bl_pwm->pwm_data.pwm)) {
pr_info("analog_pwm invalid\n");
break;
}
pr_info("analog_pwm_pointer: 0x%p\n",
bl_pwm->pwm_data.pwm);
pwm_get_state(bl_pwm->pwm_data.pwm, &pstate);
pr_info("analog_pwm state:\n"
" period: %d\n"
" duty_cycle: %d\n"
" polarity: %d\n"
" enabled: %d\n",
pstate.period, pstate.duty_cycle,
pstate.polarity, pstate.enabled);
value = bl_cbus_read(
bl_drv->data->pwm_reg[bl_pwm->pwm_port]);
pr_info("analog_pwm_reg: 0x%08x\n", value);
break;
default:
break;
}
}
pr_info("\npinmux_flag: %d\n"
"pinmux_pointer: 0x%p\n\n",
ldim_drv->pinmux_flag,
ldim_drv->pin);
if (ldim_drv->ldev_conf->cmd_size > 0) {
pr_info("table_loaded: %d\n"
"cmd_size: %d\n"
"init_on_cnt: %d\n"
"init_off_cnt: %d\n",
pr_info("table_loaded: %d\n"
"cmd_size: %d\n"
"init_on_cnt: %d\n"
"init_off_cnt: %d\n",
ldim_drv->ldev_conf->init_loaded,
ldim_drv->ldev_conf->cmd_size,
ldim_drv->ldev_conf->init_on_cnt,
@@ -647,6 +709,9 @@ static int ldim_dev_pwm_channel_register(struct bl_pwm_config_s *bl_pwm,
struct device_node *child;
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
if (ldim_debug_print)
LDIMPR("%s ok\n", __func__);
ret = of_property_read_u32(blnode, "ldim_pwm_config", &pwm_phandle);
if (ret) {
LDIMERR("not match ldim_pwm_config node\n");
@@ -694,8 +759,6 @@ static int ldim_dev_pwm_channel_register(struct bl_pwm_config_s *bl_pwm,
bl_pwm->pwm_data.port_index, bl_pwm->pwm_data.pwm);
}
LDIMPR("%s ok\n", __func__);
return ret;
}
@@ -902,6 +965,7 @@ static int ldim_dev_get_config_from_dts(struct device_node *np, int index)
int i;
int ret = 0;
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
struct bl_pwm_config_s *bl_pwm;
temp = kcalloc(LD_BLKREGNUM, sizeof(unsigned int), GFP_KERNEL);
if (temp == NULL) {
@@ -927,48 +991,77 @@ static int ldim_dev_get_config_from_dts(struct device_node *np, int index)
ret = of_property_read_string(child, "ldim_pwm_pinmux_sel", &str);
if (ret) {
LDIMERR("failed to get ldim_pwm_name\n");
strcpy(ldim_dev_config.pinmux_name, "invalid");
} else {
LDIMPR("find custome ldim_pwm_pinmux_sel: %s\n", str);
strcpy(ldim_dev_config.pinmux_name, str);
}
/* ldim pwm config */
bl_pwm = &ldim_dev_config.ldim_pwm_config;
ret = of_property_read_string(child, "ldim_pwm_port", &str);
if (ret) {
LDIMERR("failed to get ldim_pwm_port\n");
ldim_dev_config.pwm_config.pwm_port = BL_PWM_MAX;
} else {
ldim_dev_config.pwm_config.pwm_port = bl_pwm_str_to_pwm(str);
bl_pwm->pwm_port = bl_pwm_str_to_pwm(str);
LDIMPR("ldim_pwm_port: %s(%u)\n", str, bl_pwm->pwm_port);
}
LDIMPR("pwm_port: %s(%u)\n", str, ldim_dev_config.pwm_config.pwm_port);
if (ldim_dev_config.pwm_config.pwm_port < BL_PWM_MAX) {
if (bl_pwm->pwm_port < BL_PWM_MAX) {
ret = of_property_read_u32_array(child, "ldim_pwm_attr",
temp, 3);
if (ret) {
LDIMERR("failed to get ldim_pwm_attr\n");
ldim_dev_config.pwm_config.pwm_method = BL_PWM_POSITIVE;
if (ldim_dev_config.pwm_config.pwm_port == BL_PWM_VS)
ldim_dev_config.pwm_config.pwm_freq = 1;
bl_pwm->pwm_method = BL_PWM_POSITIVE;
if (bl_pwm->pwm_port == BL_PWM_VS)
bl_pwm->pwm_freq = 1;
else
ldim_dev_config.pwm_config.pwm_freq = 60;
ldim_dev_config.pwm_config.pwm_duty = 50;
bl_pwm->pwm_freq = 60;
bl_pwm->pwm_duty = 50;
} else {
ldim_dev_config.pwm_config.pwm_method = temp[0];
ldim_dev_config.pwm_config.pwm_freq = temp[1];
ldim_dev_config.pwm_config.pwm_duty = temp[2];
bl_pwm->pwm_method = temp[0];
bl_pwm->pwm_freq = temp[1];
bl_pwm->pwm_duty = temp[2];
}
LDIMPR("get pwm pol = %d, freq = %d, duty = %d%%\n",
ldim_dev_config.pwm_config.pwm_method,
ldim_dev_config.pwm_config.pwm_freq,
ldim_dev_config.pwm_config.pwm_duty);
LDIMPR(
"get ldim_pwm pol = %d, freq = %d, default duty = %d%%\n",
bl_pwm->pwm_method, bl_pwm->pwm_freq,
bl_pwm->pwm_duty);
bl_pwm_config_init(&ldim_dev_config.pwm_config);
bl_pwm_config_init(bl_pwm);
if (ldim_dev_config.pwm_config.pwm_port < BL_PWM_VS) {
ldim_dev_pwm_channel_register(
&ldim_dev_config.pwm_config, np);
if (bl_pwm->pwm_port < BL_PWM_VS)
ldim_dev_pwm_channel_register(bl_pwm, np);
}
/* analog pwm config */
bl_pwm = &ldim_dev_config.analog_pwm_config;
ret = of_property_read_string(child, "analog_pwm_port", &str);
if (ret)
bl_pwm->pwm_port = BL_PWM_MAX;
else
bl_pwm->pwm_port = bl_pwm_str_to_pwm(str);
if (bl_pwm->pwm_port < BL_PWM_VS) {
LDIMPR("find analog_pwm_port: %s(%u)\n", str, bl_pwm->pwm_port);
ret = of_property_read_u32_array(child, "analog_pwm_attr",
temp, 5);
if (ret) {
LDIMERR("failed to get analog_pwm_attr\n");
} else {
bl_pwm->pwm_method = temp[0];
bl_pwm->pwm_freq = temp[1];
bl_pwm->pwm_duty_max = temp[2];
bl_pwm->pwm_duty_min = temp[3];
bl_pwm->pwm_duty = temp[4];
}
LDIMPR(
"get analog_pwm pol = %d, freq = %d, duty_max = %d%%, duty_min = %d%%, default duty = %d%%\n",
bl_pwm->pwm_method, bl_pwm->pwm_freq,
bl_pwm->pwm_duty_max, bl_pwm->pwm_duty_min,
bl_pwm->pwm_duty);
bl_pwm_config_init(bl_pwm);
ldim_dev_pwm_channel_register(bl_pwm, np);
}
ret = of_property_read_u32_array(child, "en_gpio_on_off", temp, 3);
@@ -1643,12 +1736,14 @@ static int ldim_dev_probe(struct platform_device *pdev)
ldim_dev_get_config_from_dts(pdev->dev.of_node,
ldim_drv->dev_index);
ldim_dev_class_create();
ldim_dev_add_driver(ldim_drv);
/* init ldim function */
if (ldim_drv->valid_flag)
ldim_drv->init();
LDIMPR("%s OK\n", __func__);
}
/* init ldim function */
if (ldim_drv->valid_flag)
ldim_drv->init();
LDIMPR("%s OK\n", __func__);
return 0;
}
@@ -1657,10 +1752,11 @@ static int __exit ldim_dev_remove(struct platform_device *pdev)
{
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
if (ldim_drv->dev_index != 0xff)
if (ldim_drv->dev_index != 0xff) {
ldim_dev_remove_driver(ldim_drv);
LDIMPR("%s OK\n", __func__);
}
LDIMPR("%s OK\n", __func__);
return 0;
}

View File

@@ -25,7 +25,9 @@
/*20180820: pq tooling support, espically optimize some alg parameters */
/*20181101: fix ldim_op_func null mistake, add new spi api support */
/*20181203: add 50/60hz change & iw7027 error handle support */
#define LDIM_DRV_VER "20181203"
/*20181220: add tl1 support*/
/*20190103: add analog pwm support*/
#define LDIM_DRV_VER "20190103"
extern unsigned char ldim_debug_print;

View File

@@ -48,7 +48,8 @@ static int ob3350_hw_init_on(void)
ldim_drv->ldev_conf->en_gpio_on);
mdelay(2);
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->pwm_config));
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->ldim_pwm_config));
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->analog_pwm_config));
ldim_drv->pinmux_ctrl(1);
mdelay(20);
@@ -62,7 +63,8 @@ static int ob3350_hw_init_off(void)
ldim_gpio_set(ldim_drv->ldev_conf->en_gpio,
ldim_drv->ldev_conf->en_gpio_off);
ldim_drv->pinmux_ctrl(0);
ldim_pwm_off(&(ldim_drv->ldev_conf->pwm_config));
ldim_pwm_off(&(ldim_drv->ldev_conf->ldim_pwm_config));
ldim_pwm_off(&(ldim_drv->ldev_conf->analog_pwm_config));
return 0;
}
@@ -89,12 +91,22 @@ static int ob3350_smr(unsigned short *buf, unsigned char len)
level = buf[0];
val = dim_min + ((level * (dim_max - dim_min)) / LD_DATA_MAX);
ldim_drv->ldev_conf->pwm_config.pwm_duty = val;
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->pwm_config));
ldim_drv->ldev_conf->ldim_pwm_config.pwm_duty = val;
ldim_set_duty_pwm(&(ldim_drv->ldev_conf->ldim_pwm_config));
return 0;
}
static void ob3350_dim_range_update(void)
{
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
struct ldim_dev_config_s *ldim_dev;
ldim_dev = ldim_drv->ldev_conf;
ldim_dev->dim_max = ldim_dev->ldim_pwm_config.pwm_duty_max;
ldim_dev->dim_min = ldim_dev->ldim_pwm_config.pwm_duty_min;
}
static int ob3350_power_on(void)
{
if (ob3350_on_flag) {
@@ -138,7 +150,7 @@ static ssize_t ob3350_show(struct class *class,
ldim_drv->ldev_conf->en_gpio_off,
ldim_drv->ldev_conf->dim_max,
ldim_drv->ldev_conf->dim_min,
ldim_drv->ldev_conf->pwm_config.pwm_duty);
ldim_drv->ldev_conf->ldim_pwm_config.pwm_duty);
}
return ret;
@@ -151,6 +163,12 @@ static struct class_attribute ob3350_class_attrs[] = {
static int ob3350_ldim_driver_update(struct aml_ldim_driver_s *ldim_drv)
{
struct ldim_dev_config_s *ldim_dev = ldim_drv->ldev_conf;
ldim_dev->ldim_pwm_config.pwm_duty_max = ldim_dev->dim_max;
ldim_dev->ldim_pwm_config.pwm_duty_min = ldim_dev->dim_min;
ldim_dev->dim_range_update = ob3350_dim_range_update;
ldim_drv->device_power_on = ob3350_power_on;
ldim_drv->device_power_off = ob3350_power_off;
ldim_drv->device_bri_update = ob3350_smr;

View File

@@ -197,5 +197,14 @@ extern void bl_pwm_ctrl(struct bl_pwm_config_s *bl_pwm, int status);
#define BL_GPIO_OUTPUT_HIGH 1
#define BL_GPIO_INPUT 2
static inline unsigned int bl_do_div(unsigned long long num, unsigned int den)
{
unsigned long long ret = num;
do_div(ret, den);
return (unsigned int)ret;
}
#endif