mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 23:24:22 -04:00
DLKM: add ktd3136 backlight
ktd3136_bl: suport ktd3136 backlight IC NO_PROP_NEEDED: new backlight IC for new project Change-Id: I0d67b497d7f8b09672b1279ae063a44265259885 Signed-off-by: hujing3 <hujing3@lenovo.com> Reviewed-on: https://gerrit.mot.com/1673372 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
d303777d9e
commit
2e29cae7b7
5 changed files with 853 additions and 0 deletions
14
drivers/backlight/ktd3136/Android.mk
Normal file
14
drivers/backlight/ktd3136/Android.mk
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ktd3136_bl.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true)
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/
|
||||
else
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
endif
|
||||
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
5
drivers/backlight/ktd3136/Kbuild
Normal file
5
drivers/backlight/ktd3136/Kbuild
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m += ktd3136_bl.o
|
||||
10
drivers/backlight/ktd3136/Makefile
Normal file
10
drivers/backlight/ktd3136/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
704
drivers/backlight/ktd3136/ktd3136_bl.c
Normal file
704
drivers/backlight/ktd3136/ktd3136_bl.c
Normal file
|
|
@ -0,0 +1,704 @@
|
|||
/*
|
||||
* KTD3136_BL Driver
|
||||
*
|
||||
* SiliconMitus KTD3136 Backlight driver chip
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/backlight.h>
|
||||
#if defined(CONFIG_FB)
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/fb.h>
|
||||
#endif
|
||||
|
||||
#include "ktd3136_bl.h"
|
||||
|
||||
#define KTD3136_LED_DEV "ktd3136-BL"
|
||||
#define KTD3136_NAME "ktd3136-bl"
|
||||
#define KTD3136_CHIP_ID 0x18
|
||||
|
||||
static int platform_read_i2c_block(struct i2c_client *client, char *writebuf,
|
||||
int writelen, char *readbuf, int readlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (writelen > 0) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 2);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c read error.\n",
|
||||
__func__);
|
||||
} else {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s:i2c read error.\n", __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ktd3136_read_reg(struct i2c_client *client, u8 addr, u8 *val)
|
||||
{
|
||||
return platform_read_i2c_block(client, &addr, 1, val, 1);
|
||||
}
|
||||
|
||||
static int platform_write_i2c_block(struct i2c_client *client, char *writebuf, int writelen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c write error.\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ktd3136_write_reg(struct i2c_client *client, u8 addr, const u8 val)
|
||||
{
|
||||
u8 buf[2] = {0};
|
||||
|
||||
buf[0] = addr;
|
||||
buf[1] = val;
|
||||
return platform_write_i2c_block(client, buf, sizeof(buf));
|
||||
}
|
||||
static void ktd3136_hwen_pin_ctrl(struct ktd3136_data *drvdata, int en)
|
||||
{
|
||||
if (gpio_is_valid(drvdata->hwen_gpio)) {
|
||||
if (en) {
|
||||
pr_debug("hwen pin is going to be high!---<%d>\n", en);
|
||||
gpio_set_value(drvdata->hwen_gpio, true);
|
||||
} else {
|
||||
pr_debug("hwen pin is going to be low!---<%d>\n", en);
|
||||
gpio_set_value(drvdata->hwen_gpio, false);
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ktd3136_gpio_init(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
if (gpio_is_valid(drvdata->hwen_gpio)) {
|
||||
ret = gpio_request(drvdata->hwen_gpio, "ktd_hwen_gpio");
|
||||
if (ret<0) {
|
||||
pr_err("failed to request gpio\n");
|
||||
return -1;
|
||||
}
|
||||
ret = gpio_direction_output(drvdata->hwen_gpio, 0);
|
||||
pr_debug(" request gpio init\n");
|
||||
if (ret<0) {
|
||||
pr_err("failed to set output");
|
||||
gpio_free(drvdata->hwen_gpio);
|
||||
return ret;
|
||||
}
|
||||
pr_debug("gpio is valid!\n");
|
||||
ktd3136_hwen_pin_ctrl(drvdata, 1);
|
||||
}
|
||||
|
||||
pr_info("%s exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
static int ktd3136_masked_write(struct i2c_client *client, int reg, u8 mask, u8 val)
|
||||
{
|
||||
int rc;
|
||||
u8 temp;
|
||||
|
||||
rc = ktd3136_read_reg(client, reg, &temp);
|
||||
if (rc < 0) {
|
||||
pr_err("failed to read reg=0x%x, rc=%d\n", reg, rc);
|
||||
} else {
|
||||
temp &= ~mask;
|
||||
temp |= val & mask;
|
||||
rc = ktd3136_write_reg(client, reg, temp);
|
||||
if (rc<0) {
|
||||
pr_err( "failed to write masked data. reg=%03x, rc=%d\n", reg, rc);
|
||||
}
|
||||
}
|
||||
|
||||
ktd3136_read_reg(client, reg, &temp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ktd3136_bl_enable_channel(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (drvdata->channel == 0) {
|
||||
//default value for mode Register, all channel disabled.
|
||||
pr_debug("all channels are going to be disabled\n");
|
||||
ret = ktd3136_write_reg(drvdata->client, REG_PWM, 0x18);//b0001 1000
|
||||
} else if (drvdata->channel == 3) {
|
||||
pr_debug("turn all channel on!\n");
|
||||
ret = ktd3136_masked_write(drvdata->client, REG_PWM, 0x07, 0x07);
|
||||
} else if (drvdata->channel == 2) {
|
||||
ret = ktd3136_masked_write(drvdata->client, REG_PWM, 0x07, 0x03);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static void ktd3136_pwm_mode_enable(struct ktd3136_data *drvdata, bool en)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
if (en) {
|
||||
if (drvdata->pwm_mode) {
|
||||
pr_debug("already activated!\n");
|
||||
} else {
|
||||
drvdata->pwm_mode = en;
|
||||
}
|
||||
ktd3136_masked_write(drvdata->client, REG_PWM, 0x80, 0x80);
|
||||
} else {
|
||||
if (drvdata->pwm_mode) {
|
||||
drvdata->pwm_mode = en;
|
||||
}
|
||||
ktd3136_masked_write(drvdata->client, REG_PWM, 0x80, 0x00);
|
||||
}
|
||||
|
||||
ktd3136_read_reg(drvdata->client, REG_PWM, &value);
|
||||
pr_debug("current pwm_mode is --<%x>\n", value);
|
||||
}
|
||||
static int ktd_find_bit(int x)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while ((x = x >> 1))
|
||||
i++;
|
||||
|
||||
return i+1;
|
||||
}
|
||||
|
||||
static void ktd3136_ramp_setting(struct ktd3136_data *drvdata)
|
||||
{
|
||||
unsigned int max_time = 16384;
|
||||
int temp = 0;
|
||||
|
||||
if (drvdata->ramp_on_time == 0) {//512us
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0xf0, 0x00);
|
||||
pr_debug("rampon time is 0 \n");
|
||||
} else if (drvdata->ramp_on_time > max_time) {
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0xf0, 0xf0);
|
||||
pr_debug("rampon time is max \n");
|
||||
} else {
|
||||
temp = ktd_find_bit(drvdata->ramp_on_time);
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0xf0, temp<<4);
|
||||
pr_debug("temp is %d\n", temp);
|
||||
}
|
||||
|
||||
if (drvdata->ramp_off_time == 0) {//512us
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0x0f, 0x00);
|
||||
pr_debug("rampoff time is 0 \n");
|
||||
} else if (drvdata->ramp_off_time > max_time) {
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0x0f, 0x0f);
|
||||
pr_debug("rampoff time is max \n");
|
||||
} else {
|
||||
temp = ktd_find_bit(drvdata->ramp_off_time);
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0x0f, temp);
|
||||
pr_debug("temp is %d\n", temp);
|
||||
}
|
||||
|
||||
}
|
||||
static void ktd3136_transition_ramp(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int reg_i2c, reg_pwm, temp;
|
||||
|
||||
if (drvdata->i2c_trans_dim >= 1024) {
|
||||
reg_i2c = 0xf;
|
||||
} else if (drvdata->i2c_trans_dim < 128) {
|
||||
reg_i2c = 0x0;
|
||||
} else {
|
||||
temp =drvdata->i2c_trans_dim/64;
|
||||
reg_i2c = temp-1;
|
||||
pr_debug("reg_i2c is --<0x%x>\n", reg_i2c);
|
||||
}
|
||||
|
||||
if(drvdata->pwm_trans_dim >= 256){
|
||||
reg_pwm = 0x7;
|
||||
}else if(drvdata->pwm_trans_dim < 4){
|
||||
reg_pwm = 0x0;
|
||||
}else{
|
||||
temp = ktd_find_bit(drvdata->pwm_trans_dim);
|
||||
reg_pwm = temp -2;
|
||||
pr_debug("temp is %d\n", temp);
|
||||
}
|
||||
|
||||
ktd3136_masked_write(drvdata->client, REG_TRANS_RAMP, 0x70, reg_pwm);
|
||||
ktd3136_masked_write(drvdata->client, REG_TRANS_RAMP, 0x0f, reg_i2c);
|
||||
|
||||
}
|
||||
|
||||
static int ktd3136_backlight_init(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
u8 value;
|
||||
u8 update_value;
|
||||
pr_info("%s enter.\n", __func__);
|
||||
update_value = (drvdata->ovp_level == 32) ? 0x20 : 0x00;
|
||||
(drvdata->induct_current == 2600) ? update_value |=0x08 : update_value;
|
||||
(drvdata->frequency == 1000) ? update_value |=0x40: update_value;
|
||||
|
||||
ktd3136_write_reg(drvdata->client, REG_CONTROL, update_value | 0x06); /* Linear default*/
|
||||
ktd3136_bl_enable_channel(drvdata);
|
||||
if (drvdata->pwm_mode) {
|
||||
ktd3136_pwm_mode_enable(drvdata, true);
|
||||
} else {
|
||||
ktd3136_pwm_mode_enable(drvdata, false);
|
||||
}
|
||||
ktd3136_ramp_setting(drvdata);
|
||||
ktd3136_transition_ramp(drvdata);
|
||||
ktd3136_read_reg(drvdata->client, REG_CONTROL, &value);
|
||||
pr_debug("read control register -before--<0x%x> -after--<0x%x> \n",
|
||||
update_value, value);
|
||||
|
||||
pr_info("%s exit\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ktd3136_backlight_enable(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
pr_info("%s enter.\n", __func__);
|
||||
ktd3136_masked_write(drvdata->client, REG_MODE, 0xf8, drvdata->full_scale_led);
|
||||
drvdata->enable = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ktd3136_set_brightness(struct ktd3136_data *drvdata, int brt_val)
|
||||
{
|
||||
pr_info("%s brt_val is %d\n", __func__, brt_val);
|
||||
|
||||
if (drvdata->enable == false)
|
||||
ktd3136_backlight_init(drvdata);
|
||||
|
||||
if (brt_val>0) {
|
||||
ktd3136_masked_write(drvdata->client, REG_MODE, 0x01, 0x01); //enalbe bl mode
|
||||
} else {
|
||||
ktd3136_masked_write(drvdata->client, REG_MODE, 0x01, 0x00); //disable bl mode
|
||||
}
|
||||
if (drvdata->using_lsb) {
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_LSB, 0x07, brt_val);
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_MSB, 0xff, brt_val>>3);
|
||||
} else {
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_LSB, 0x07, ktd3136_brightness_table_reg4[brt_val]);
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_MSB, 0xff, ktd3136_brightness_table_reg5[brt_val]);
|
||||
}
|
||||
|
||||
if (drvdata->enable == false)
|
||||
ktd3136_backlight_enable(drvdata);
|
||||
|
||||
drvdata->brightness = brt_val;
|
||||
|
||||
if (drvdata->brightness == 0)
|
||||
drvdata->enable = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
static int ktd3136_bl_get_brightness(struct backlight_device *bl_dev)
|
||||
{
|
||||
return bl_dev->props.brightness;
|
||||
}
|
||||
|
||||
static int ktd3136_bl_update_status(struct backlight_device *bl_dev)
|
||||
{
|
||||
struct ktd3136_data *drvdata = bl_get_data(bl_dev);
|
||||
int brt;
|
||||
|
||||
if (bl_dev->props.state & BL_CORE_SUSPENDED)
|
||||
bl_dev->props.brightness = 0;
|
||||
|
||||
brt = bl_dev->props.brightness;
|
||||
/*
|
||||
* Brightness register should always be written
|
||||
* not only register based mode but also in PWM mode.
|
||||
*/
|
||||
return ktd3136_set_brightness(drvdata, brt);
|
||||
}
|
||||
|
||||
static const struct backlight_ops ktd3136_bl_ops = {
|
||||
.update_status = ktd3136_bl_update_status,
|
||||
.get_brightness = ktd3136_bl_get_brightness,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int ktd3136_backlight_reset(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
ktd3136_masked_write(drvdata->client, REG_SW_RESET, 0x01, 0x01);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ktd3136_check_id(struct ktd3136_data *drvdata)
|
||||
{
|
||||
u8 value=0;
|
||||
int err = 0;
|
||||
ktd3136_read_reg(drvdata->client, 0x00, &value);
|
||||
pr_info("%s: ID check: %x0x\n", __func__, value);
|
||||
if (value != KTD3136_CHIP_ID) {
|
||||
pr_err("%s : ID check err\n", __func__);
|
||||
err = -EINVAL;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ktd3136_check_status(struct ktd3136_data *drvdata)
|
||||
{
|
||||
u8 value=0;
|
||||
|
||||
ktd3136_read_reg(drvdata->client, REG_STATUS, &value);
|
||||
if (value) {
|
||||
pr_err("status bit has been change! <%x>", value);
|
||||
|
||||
if (value & RESET_CONDITION_BITS) {
|
||||
ktd3136_backlight_reset(drvdata);
|
||||
ktd3136_backlight_init(drvdata);
|
||||
ktd3136_backlight_enable(drvdata);
|
||||
}
|
||||
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB)
|
||||
static int fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
int *blank;
|
||||
struct fb_event *evdata = data;
|
||||
struct ktd3136_data *drvdata =
|
||||
container_of(self, struct ktd3136_data, fb_notif);
|
||||
|
||||
/*
|
||||
* FB_EVENT_BLANK(0x09): A hardware display blank change occurred.
|
||||
* FB_EARLY_EVENT_BLANK(0x10): A hardware display blank early change
|
||||
* occurred.
|
||||
*/
|
||||
if (evdata && evdata->data && (event == FB_EARLY_EVENT_BLANK)) {
|
||||
blank = evdata->data;
|
||||
if (*blank == FB_BLANK_POWERDOWN)
|
||||
drvdata->enable = false;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __ktd3136_work(struct ktd3136_data *led,
|
||||
enum led_brightness value)
|
||||
{
|
||||
mutex_lock(&led->lock);
|
||||
ktd3136_set_brightness(led, value);
|
||||
mutex_unlock(&led->lock);
|
||||
}
|
||||
|
||||
static void ktd3136_work(struct work_struct *work)
|
||||
{
|
||||
struct ktd3136_data *drvdata = container_of(work,
|
||||
struct ktd3136_data, work);
|
||||
|
||||
__ktd3136_work(drvdata, drvdata->led_dev.brightness);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void ktd3136_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brt_val)
|
||||
{
|
||||
struct ktd3136_data *drvdata;
|
||||
|
||||
drvdata = container_of(led_cdev, struct ktd3136_data, led_dev);
|
||||
|
||||
schedule_work(&drvdata->work);
|
||||
}
|
||||
|
||||
static void ktd3136_get_dt_data(struct device *dev, struct ktd3136_data *drvdata)
|
||||
{
|
||||
int rc;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 bl_channel, temp;
|
||||
drvdata->hwen_gpio = of_get_named_gpio(np, "ktd,hwen-gpio", 0);
|
||||
pr_info("%s hwen --<%d>\n", __func__, drvdata->hwen_gpio);
|
||||
|
||||
drvdata->pwm_mode = of_property_read_bool(np,"ktd,pwm-mode");
|
||||
pr_debug("pwmmode --<%d> \n", drvdata->pwm_mode);
|
||||
|
||||
drvdata->using_lsb = of_property_read_bool(np, "ktd,using-lsb");
|
||||
pr_info("%s using_lsb --<%d>\n", __func__, drvdata->using_lsb);
|
||||
|
||||
if (drvdata->using_lsb) {
|
||||
drvdata->default_brightness = 0x7ff;
|
||||
drvdata->max_brightness = 2047;
|
||||
} else {
|
||||
drvdata->default_brightness = 0xff;
|
||||
drvdata->max_brightness = 255;
|
||||
}
|
||||
rc = of_property_read_u32(np, "ktd,pwm-frequency", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid pwm-frequency!\n");
|
||||
} else {
|
||||
drvdata->pwm_period = temp;
|
||||
pr_debug("pwm-frequency --<%d> \n", drvdata->pwm_period);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,bl-fscal-led", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid backlight full-scale led current!\n");
|
||||
} else {
|
||||
drvdata->full_scale_led = temp;
|
||||
pr_debug("full-scale led current --<%d mA> \n", drvdata->full_scale_led);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,turn-on-ramp", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid ramp timing ,,turnon!\n");
|
||||
} else {
|
||||
drvdata->ramp_on_time = temp;
|
||||
pr_debug("ramp on time --<%d ms> \n", drvdata->ramp_on_time);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,turn-off-ramp", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid ramp timing ,,turnoff!\n");
|
||||
} else {
|
||||
drvdata->ramp_off_time = temp;
|
||||
pr_debug("ramp off time --<%d ms> \n", drvdata->ramp_off_time);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,pwm-trans-dim", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid pwm-tarns-dim value!\n");
|
||||
}
|
||||
else {
|
||||
drvdata->pwm_trans_dim = temp;
|
||||
pr_debug("pwm trnasition dimming --<%d ms> \n", drvdata->pwm_trans_dim);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,i2c-trans-dim", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid i2c-trans-dim value !\n");
|
||||
} else {
|
||||
drvdata->i2c_trans_dim = temp;
|
||||
pr_debug("i2c transition dimming --<%d ms>\n", drvdata->i2c_trans_dim);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,bl-channel", &bl_channel);
|
||||
if (rc) {
|
||||
pr_err("Invalid channel setup\n");
|
||||
} else {
|
||||
drvdata->channel = bl_channel;
|
||||
pr_debug("bl-channel --<%x> \n", drvdata->channel);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,ovp-level", &temp);
|
||||
if (!rc) {
|
||||
drvdata->ovp_level = temp;
|
||||
pr_debug("ovp-level --<%d> --temp <%d>\n", drvdata->ovp_level, temp);
|
||||
}else
|
||||
pr_err("Invalid OVP level!\n");
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,switching-frequency", &temp);
|
||||
if (!rc) {
|
||||
drvdata->frequency = temp;
|
||||
pr_debug("switching frequency --<%d> \n", drvdata->frequency);
|
||||
} else {
|
||||
pr_err("Invalid Frequency value!\n");
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,inductor-current", &temp);
|
||||
if (!rc) {
|
||||
drvdata->induct_current = temp;
|
||||
pr_debug("inductor current limit --<%d> \n", drvdata->induct_current);
|
||||
} else
|
||||
pr_err("invalid induct_current limit\n");
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,flash-timeout", &temp);
|
||||
if (!rc) {
|
||||
drvdata->flash_timeout = temp;
|
||||
pr_debug("flash timeout --<%d> \n", drvdata->flash_timeout);
|
||||
} else {
|
||||
pr_err("invalid flash-time value!\n");
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,flash-current", &temp);
|
||||
if (!rc) {
|
||||
drvdata->flash_current = temp;
|
||||
pr_debug("flash current --<0x%x> \n", drvdata->flash_current);
|
||||
} else {
|
||||
pr_err("invalid flash current value!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int ktd3136_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ktd3136_data *drvdata;
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
struct backlight_device *bl_dev;
|
||||
struct backlight_properties props;
|
||||
#endif
|
||||
int err = 0;
|
||||
|
||||
pr_info("%s enter!\n", __func__);
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
pr_err("%s : I2C_FUNC_I2C not supported\n", __func__);
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!client->dev.of_node) {
|
||||
pr_err("%s : no device node\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata = kzalloc(sizeof(struct ktd3136_data), GFP_KERNEL);
|
||||
if (drvdata == NULL) {
|
||||
pr_err("%s : kzalloc failed\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata->client = client;
|
||||
drvdata->adapter = client->adapter;
|
||||
#ifdef KTD3136_REG_CONFILCT
|
||||
pr_info("%s: client->addr=0x%x\n", __func__, client->addr);
|
||||
client->addr = KTD3136_REG_REAL;
|
||||
pr_info("%s: confilct, reset client->addr to 0x%x\n", __func__, client->addr);
|
||||
#endif
|
||||
drvdata->addr = client->addr;
|
||||
drvdata->brightness = LED_OFF;
|
||||
drvdata->enable = true;
|
||||
drvdata->led_dev.default_trigger = "bkl-trigger";
|
||||
drvdata->led_dev.name = KTD3136_LED_DEV;
|
||||
drvdata->led_dev.brightness_set = ktd3136_brightness_set;
|
||||
drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
|
||||
ktd3136_get_dt_data(&client->dev, drvdata);
|
||||
i2c_set_clientdata(client, drvdata);
|
||||
err =ktd3136_check_id(drvdata);
|
||||
if (err <0) {
|
||||
pr_err("%s : ID idenfy failed\n", __func__);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
mutex_init(&drvdata->lock);
|
||||
INIT_WORK(&drvdata->work, ktd3136_work);
|
||||
err = led_classdev_register(&client->dev, &drvdata->led_dev);
|
||||
if (err < 0) {
|
||||
pr_err("%s : Register led class failed\n", __func__);
|
||||
err = -ENODEV;
|
||||
goto err_init;
|
||||
} else {
|
||||
pr_info("%s: Register led class successful\n", __func__);
|
||||
}
|
||||
ktd3136_gpio_init(drvdata);
|
||||
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.brightness = MAX_BRIGHTNESS;
|
||||
props.max_brightness = MAX_BRIGHTNESS;
|
||||
bl_dev = backlight_device_register(KTD3136_NAME, &client->dev,
|
||||
drvdata, &ktd3136_bl_ops, &props);
|
||||
#endif
|
||||
ktd3136_backlight_init(drvdata);
|
||||
ktd3136_backlight_enable(drvdata);
|
||||
ktd3136_check_status(drvdata);
|
||||
|
||||
#if defined(CONFIG_FB)
|
||||
drvdata->fb_notif.notifier_call = fb_notifier_callback;
|
||||
err = fb_register_client(&drvdata->fb_notif);
|
||||
if (err)
|
||||
pr_err("%s : Unable to register fb_notifier: %d\n", __func__, err);
|
||||
#endif
|
||||
|
||||
pr_info("%s exit\n", __func__);
|
||||
return 0;
|
||||
|
||||
err_init:
|
||||
pr_info("%s err_init\n", __func__);
|
||||
kfree(drvdata);
|
||||
err_out:
|
||||
pr_info("%s err_out\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ktd3136_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ktd3136_data *drvdata = i2c_get_clientdata(client);
|
||||
|
||||
led_classdev_unregister(&drvdata->led_dev);
|
||||
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ktd3136_id[] = {
|
||||
{KTD3136_NAME, 0},
|
||||
{}
|
||||
};
|
||||
static struct of_device_id match_table[] = {
|
||||
{.compatible = "ktd,ktd3136",}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ktd3136_id);
|
||||
|
||||
static struct i2c_driver ktd3136_i2c_driver = {
|
||||
.probe = ktd3136_probe,
|
||||
.remove = ktd3136_remove,
|
||||
.id_table = ktd3136_id,
|
||||
.driver = {
|
||||
.name = KTD3136_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_i2c_driver(ktd3136_i2c_driver);
|
||||
MODULE_DESCRIPTION("Backlight driver for ktd3136");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
120
drivers/backlight/ktd3136/ktd3136_bl.h
Normal file
120
drivers/backlight/ktd3136/ktd3136_bl.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#ifndef _KTD3136_REG_H_
|
||||
#define _KTD3136_REG_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
/*********************************************************
|
||||
*
|
||||
* kernel version
|
||||
*
|
||||
********************************************************/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||
#define KERNEL_ABOVE_4_14
|
||||
#endif
|
||||
|
||||
#undef pr_debug
|
||||
#define pr_debug pr_info
|
||||
|
||||
/*********************************************************
|
||||
*
|
||||
* kernel version
|
||||
*
|
||||
********************************************************/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||
#define KERNEL_ABOVE_4_14
|
||||
#endif
|
||||
|
||||
#define KTD3136_REG_CONFILCT
|
||||
#ifdef KTD3136_REG_CONFILCT
|
||||
#define KTD3136_REG_REAL 0x36
|
||||
#endif
|
||||
|
||||
#define MAX_BRIGHTNESS (2047)
|
||||
#define BANK_NONE 0x00
|
||||
#define REG_DEV_ID 0x00
|
||||
#define REG_SW_RESET 0x01
|
||||
#define REG_MODE 0x02
|
||||
#define REG_CONTROL 0x03
|
||||
#define REG_RATIO_LSB 0x04
|
||||
#define REG_RATIO_MSB 0x05
|
||||
#define REG_PWM 0x06
|
||||
#define REG_RAMP_ON 0x07
|
||||
#define REG_TRANS_RAMP 0x08
|
||||
#define REG_FLASH_SETTING 0x09
|
||||
#define REG_STATUS 0x0A
|
||||
#define BIT_CH3_FAULT BIT(7)
|
||||
#define BIT_CH2_FAULT BIT(6)
|
||||
#define BIT_CH1_FAULT BIT(5)
|
||||
#define BIT_FLASH_TIMEOUT BIT(4)
|
||||
#define BIT_OVP BIT(3)
|
||||
#define BIT_UVLO BIT(2)
|
||||
#define BIT_OCP BIT(1)
|
||||
#define BIT_THERMAL_SHUTDOWN BIT(0)
|
||||
|
||||
#define RESET_CONDITION_BITS (BIT_CH3_FAULT | BIT_CH2_FAULT | BIT_CH1_FAULT | BIT_OVP | BIT_OCP)
|
||||
|
||||
|
||||
int ktd3136_brightness_table_reg4[256] = {0x01,0x02,0x04,0x04,0x07,0x02,0x00,0x06,0x04,0x02,0x03,0x04,0x05,0x06,0x02,0x06,0x02,
|
||||
0x06,0x02,0x06,0x02,0x06,0x02,0x04,0x05,0x06,0x05,0x03,0x00,0x05,0x02,0x06,0x02,0x06,0x02,0x06,0x02,0x06,0x02,0x06,
|
||||
0x02,0x06,0x02,0x06,0x02,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x05,0x07,
|
||||
0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,
|
||||
0x04,0x05,0x06,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x06,0x05,
|
||||
0x04,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x05,0x03,0x01,0x07,0x05,0x03,0x01,0x07,0x05,0x03,
|
||||
0x01,0x07,0x05,0x03,0x00,0x05,0x02,0x07,0x04,0x01,0x06,0x03,0x00,0x05,0x02,0x07,0x04,0x01,0x06,0x03,0x00,0x05,0x02,
|
||||
0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,
|
||||
0x03,0x07,0x03,0x07,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,
|
||||
0x04,0x07,0x02,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,
|
||||
0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,
|
||||
0x03,0x05,0x07,0x01,0x03,0x04,0x05,0x06,0x07};
|
||||
|
||||
int ktd3136_brightness_table_reg5[256] = {0x00,0x06,0x0C,0x11,0x15,0x1A,0x1E,0x21,0x25,0x29,0x2C,0x2F,0x32,0x35,0x38,0x3A,0x3D,
|
||||
0x3F,0x42,0x44,0x47,0x49,0x4C,0x4E,0x50,0x52,0x54,0x56,0x58,0x59,0x5B,0x5C,0x5E,0x5F,0x61,0x62,0x64,0x65,0x67,0x68,
|
||||
0x6A,0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,0x75,0x77,0x78,0x7A,0x7B,0x7C,0x7E,0x7F,0x80,0x82,0x83,0x85,0x86,0x87,0x88,
|
||||
0x8A,0x8B,0x8C,0x8D,0x8F,0x90,0x91,0x92,0x94,0x95,0x96,0x97,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA1,0xA2,0xA3,0xA4,
|
||||
0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xB9,0xBA,0xBB,
|
||||
0xBC,0xBD,0xBE,0xBF,0xC0,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCC,0xCD,0xCE,
|
||||
0xCF,0xCF,0xD0,0xD1,0xD2,0xD2,0xD3,0xD3,0xD4,0xD5,0xD5,0xD6,0xD7,0xD7,0xD8,0xD8,0xD9,0xDA,0xDA,0xDB,0xDC,0xDC,0xDD,
|
||||
0xDD,0xDE,0xDE,0xDF,0xDF,0xE0,0xE0,0xE1,0xE1,0xE2,0xE2,0xE3,0xE3,0xE4,0xE4,0xE5,0xE5,0xE6,0xE6,0xE7,0xE7,0xE8,0xE8,
|
||||
0xE9,0xE9,0xEA,0xEA,0xEB,0xEB,0xEC,0xEC,0xEC,0xED,0xED,0xEE,0xEE,0xEE,0xEF,0xEF,0xEF,0xF0,0xF0,0xF1,0xF1,0xF1,0xF2,
|
||||
0xF2,0xF2,0xF3,0xF3,0xF3,0xF4,0xF4,0xF4,0xF4,0xF5,0xF5,0xF5,0xF5,0xF6,0xF6,0xF6,0xF6,0xF7,0xF7,0xF7,0xF7,0xF8,0xF8,
|
||||
0xF8,0xF8,0xF9,0xF9,0xF9,0xF9,0xFA,0xFA,0xFA,0xFA,0xFB,0xFB,0xFB,0xFB,0xFC,0xFC,0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,
|
||||
0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
|
||||
struct ktd3136_data {
|
||||
struct led_classdev led_dev;
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *adapter;
|
||||
unsigned short addr;
|
||||
struct mutex lock;
|
||||
struct work_struct work;
|
||||
enum led_brightness brightness;
|
||||
#ifdef CONFIG_FB
|
||||
struct notifier_block fb_notif;
|
||||
#endif
|
||||
bool enable;
|
||||
u8 pwm_cfg;
|
||||
u8 boost_ctl;
|
||||
u8 full_scale_current;
|
||||
bool brt_code_enable;
|
||||
u16 *brt_code_table;
|
||||
int hwen_gpio;
|
||||
bool pwm_mode;
|
||||
bool using_lsb;
|
||||
unsigned int pwm_period;
|
||||
unsigned int full_scale_led;
|
||||
unsigned int ramp_on_time;
|
||||
unsigned int ramp_off_time;
|
||||
unsigned int pwm_trans_dim;
|
||||
unsigned int i2c_trans_dim;
|
||||
unsigned int channel;
|
||||
unsigned int ovp_level;
|
||||
unsigned int frequency;
|
||||
unsigned int default_brightness;
|
||||
unsigned int max_brightness;
|
||||
unsigned int induct_current;
|
||||
unsigned int flash_current;
|
||||
unsigned int flash_timeout;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue