backlight: Add wleds driver aw99703

backlight:
Add wleds aw99703 initial driver.

Change-Id: Ie40380796126e59391043dc80cb8f46c8784c38e
Signed-off-by: wangyq13 <wangyq13@lenovo.com>
Reviewed-on: https://gerrit.mot.com/1584340
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
wangyq13 2020-05-28 14:59:28 +08:00 • committed by Yeqing Wang
commit 7896edaeec
5 changed files with 1000 additions and 0 deletions

View file

@ -0,0 +1,14 @@
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := leds_aw99703.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

View 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 += leds_aw99703.o

View 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

View file

@ -0,0 +1,719 @@
/*
* aw99703.c aw99703 backlight module
*
* Version: v1.0.3
*
* Copyright (c) 2019 AWINIC Technology CO., LTD
*
* Author: Joseph <zhangzetao@awinic.com.cn>
*
* 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.
*/
#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/version.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/backlight.h>
#include "leds_aw99703.h"
#define AW99703_LED_DEV "aw99703-bl"
#define AW99703_NAME "aw99703-bl"
#define AW99703_VERSION "v1.0.3"
struct aw99703_data *g_aw99703_data;
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 aw99703_i2c_read(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 aw99703_i2c_write(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 aw99703_hwen_pin_ctrl(struct aw99703_data *drvdata, int en)
{
if (gpio_is_valid(drvdata->hwen_gpio)) {
if (en) {
pr_info("hwen pin is going to be high!---<%d>\n", en);
gpio_set_value(drvdata->hwen_gpio, true);
usleep_range(3500, 4000);
} else {
pr_info("hwen pin is going to be low!---<%d>\n", en);
gpio_set_value(drvdata->hwen_gpio, false);
usleep_range(1000, 2000);
}
}
}
static int aw99703_gpio_init(struct aw99703_data *drvdata)
{
int ret;
if (gpio_is_valid(drvdata->hwen_gpio)) {
ret = gpio_request(drvdata->hwen_gpio, "hwen_gpio");
if (ret < 0) {
pr_err("failed to request gpio\n");
return -1;
}
ret = gpio_direction_output(drvdata->hwen_gpio, 0);
pr_info(" request gpio init\n");
if (ret < 0) {
pr_err("failed to set output");
gpio_free(drvdata->hwen_gpio);
return ret;
}
pr_info("gpio is valid %d!\n",drvdata->hwen_gpio);
aw99703_hwen_pin_ctrl(drvdata, 1);
}
return 0;
}
static int aw99703_i2c_write_bit(struct i2c_client *client,
unsigned int reg_addr, unsigned int mask, unsigned char reg_data)
{
unsigned char reg_val = 0;
aw99703_i2c_read(client, reg_addr, &reg_val);
reg_val &= mask;
reg_val |= reg_data;
aw99703_i2c_write(client, reg_addr, reg_val);
return 0;
}
static int aw99703_brightness_map(unsigned int level)
{
/*MAX_LEVEL_256*/
if (g_aw99703_data->bl_map == 1) {
if (level == 255)
return 2047;
return level * 8;
}
/*MAX_LEVEL_1024*/
if (g_aw99703_data->bl_map == 2)
return level * 2;
/*MAX_LEVEL_2048*/
if (g_aw99703_data->bl_map == 3)
return level;
return level;
}
static int aw99703_bl_enable_channel(struct aw99703_data *drvdata)
{
int ret = 0;
if (drvdata->channel == 3) {
pr_info("%s turn all channel on!\n", __func__);
ret = aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_LEDCUR,
AW99703_LEDCUR_CHANNEL_MASK,
AW99703_LEDCUR_CH3_ENABLE |
AW99703_LEDCUR_CH2_ENABLE |
AW99703_LEDCUR_CH1_ENABLE);
} else if (drvdata->channel == 2) {
pr_info("%s turn two channel on!\n", __func__);
ret = aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_LEDCUR,
AW99703_LEDCUR_CHANNEL_MASK,
AW99703_LEDCUR_CH2_ENABLE |
AW99703_LEDCUR_CH1_ENABLE);
} else if (drvdata->channel == 1) {
pr_info("%s turn one channel on!\n", __func__);
ret = aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_LEDCUR,
AW99703_LEDCUR_CHANNEL_MASK,
AW99703_LEDCUR_CH1_ENABLE);
} else {
pr_info("%s all channels are going to be disabled\n", __func__);
ret = aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_LEDCUR,
AW99703_LEDCUR_CHANNEL_MASK,
0x98);
}
return ret;
}
static void aw99703_pwm_mode_enable(struct aw99703_data *drvdata)
{
if (drvdata->pwm_mode) {
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_MODE,
AW99703_MODE_PDIS_MASK,
AW99703_MODE_PDIS_ENABLE);
pr_info("%s pwm_mode is enable\n", __func__);
} else {
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_MODE,
AW99703_MODE_PDIS_MASK,
AW99703_MODE_PDIS_DISABLE);
pr_info("%s pwm_mode is disable\n", __func__);
}
}
static void aw99703_ramp_setting(struct aw99703_data *drvdata)
{
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_TURNCFG,
AW99703_TURNCFG_ON_TIM_MASK,
drvdata->ramp_on_time << 4);
pr_info("%s drvdata->ramp_on_time is 0x%x\n",
__func__, drvdata->ramp_on_time);
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_TURNCFG,
AW99703_TURNCFG_OFF_TIM_MASK,
drvdata->ramp_off_time);
pr_info("%s drvdata->ramp_off_time is 0x%x\n",
__func__, drvdata->ramp_off_time);
}
static void aw99703_transition_ramp(struct aw99703_data *drvdata)
{
pr_info("%s enter\n", __func__);
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_TRANCFG,
AW99703_TRANCFG_PWM_TIM_MASK,
drvdata->pwm_trans_dim);
pr_info("%s drvdata->pwm_trans_dim is 0x%x\n", __func__,
drvdata->pwm_trans_dim);
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_TRANCFG,
AW99703_TRANCFG_I2C_TIM_MASK,
drvdata->i2c_trans_dim);
pr_info("%s drvdata->i2c_trans_dim is 0x%x\n",
__func__, drvdata->i2c_trans_dim);
}
static int aw99703_backlight_init(struct aw99703_data *drvdata)
{
pr_info("%s enter.\n", __func__);
aw99703_pwm_mode_enable(drvdata);
/*mode:map type*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_MODE,
AW99703_MODE_MAP_MASK,
AW99703_MODE_MAP_LINEAR);
/*default OVPSEL 38V*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_BSTCTR1,
AW99703_BSTCTR1_OVPSEL_MASK,
AW99703_BSTCTR1_OVPSEL_38V);
/*switch frequency 1000kHz*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_BSTCTR1,
AW99703_BSTCTR1_SF_MASK,
AW99703_BSTCTR1_SF_1000KHZ);
/*OCP SELECT*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_BSTCTR1,
AW99703_BSTCTR1_OCPSEL_MASK,
AW99703_BSTCTR1_OCPSEL_3P3A);
/*BSTCRT2 IDCTSEL*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_BSTCTR2,
AW99703_BSTCTR2_IDCTSEL_MASK,
AW99703_BSTCTR2_IDCTSEL_10UH);
/*Backlight current full scale*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_LEDCUR,
AW99703_LEDCUR_BLFS_MASK,
drvdata->full_scale_led << 3);
aw99703_bl_enable_channel(drvdata);
aw99703_ramp_setting(drvdata);
aw99703_transition_ramp(drvdata);
return 0;
}
static int aw99703_backlight_enable(struct aw99703_data *drvdata)
{
pr_info("%s enter.\n", __func__);
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_MODE,
AW99703_MODE_WORKMODE_MASK,
AW99703_MODE_WORKMODE_BACKLIGHT);
drvdata->enable = true;
return 0;
}
int aw99703_set_brightness(struct aw99703_data *drvdata, int brt_val)
{
pr_info("%s brt_val is %d\n", __func__, brt_val);
if (drvdata->enable == false) {
aw99703_backlight_init(drvdata);
aw99703_backlight_enable(drvdata);
}
brt_val = aw99703_brightness_map(brt_val);
if (brt_val > 0) {
/*enalbe bl mode*/
/* set backlight brt_val */
aw99703_i2c_write(drvdata->client,
AW99703_REG_LEDLSB,
brt_val&0x0007);
aw99703_i2c_write(drvdata->client,
AW99703_REG_LEDMSB,
(brt_val >> 3)&0xff);
/* backlight enable */
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_MODE,
AW99703_MODE_WORKMODE_MASK,
AW99703_MODE_WORKMODE_BACKLIGHT);
} else {
/* standby mode*/
aw99703_i2c_write_bit(drvdata->client,
AW99703_REG_MODE,
AW99703_MODE_WORKMODE_MASK,
AW99703_MODE_WORKMODE_STANDBY);
}
drvdata->brightness = brt_val;
if (drvdata->brightness == 0)
drvdata->enable = false;
return 0;
}
#ifdef KERNEL_ABOVE_4_14
static int aw99703_bl_get_brightness(struct backlight_device *bl_dev)
{
return bl_dev->props.brightness;
}
static int aw99703_bl_update_status(struct backlight_device *bl_dev)
{
struct aw99703_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 aw99703_set_brightness(drvdata, brt);
}
static const struct backlight_ops aw99703_bl_ops = {
.update_status = aw99703_bl_update_status,
.get_brightness = aw99703_bl_get_brightness,
};
#endif
static int aw99703_read_chipid(struct aw99703_data *drvdata)
{
int ret = -1;
u8 value = 0;
unsigned char cnt = 0;
while (cnt < AW_READ_CHIPID_RETRIES) {
ret = aw99703_i2c_read(drvdata->client, 0x00, &value);
if (ret < 0) {
pr_err("%s: failed to read reg AW99703_REG_ID: %d\n",
__func__, ret);
}
switch (value) {
case 0x03:
pr_info("%s aw99703 detected\n", __func__);
return 0;
default:
pr_info("%s unsupported device revision (0x%x)\n",
__func__, value);
break;
}
cnt++;
msleep(AW_READ_CHIPID_RETRY_DELAY);
}
return -EINVAL;
}
static void __aw99703_work(struct aw99703_data *led,
enum led_brightness value)
{
mutex_lock(&led->lock);
aw99703_set_brightness(led, value);
mutex_unlock(&led->lock);
}
static void aw99703_work(struct work_struct *work)
{
struct aw99703_data *drvdata = container_of(work,
struct aw99703_data, work);
__aw99703_work(drvdata, drvdata->led_dev.brightness);
}
static void aw99703_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brt_val)
{
struct aw99703_data *drvdata;
drvdata = container_of(led_cdev, struct aw99703_data, led_dev);
schedule_work(&drvdata->work);
}
static void
aw99703_get_dt_data(struct device *dev, struct aw99703_data *drvdata)
{
int rc;
struct device_node *np = dev->of_node;
u32 bl_channel, temp;
drvdata->hwen_gpio = of_get_named_gpio(np, "aw99703,hwen-gpio", 0);
pr_info("%s drvdata->hwen_gpio --<%d>\n", __func__, drvdata->hwen_gpio);
rc = of_property_read_u32(np, "aw99703,pwm-mode", &drvdata->pwm_mode);
if (rc != 0)
pr_err("%s pwm-mode not found\n", __func__);
else
pr_info("%s pwm_mode=%d\n", __func__, drvdata->pwm_mode);
drvdata->using_lsb = of_property_read_bool(np, "aw99703,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, "aw99703,bl-fscal-led", &temp);
if (rc) {
pr_err("Invalid backlight full-scale led current!\n");
} else {
drvdata->full_scale_led = temp;
pr_info("%s full-scale led current --<%d mA>\n",
__func__, drvdata->full_scale_led);
}
rc = of_property_read_u32(np, "aw99703,turn-on-ramp", &temp);
if (rc) {
pr_err("Invalid ramp timing ,turnon!\n");
} else {
drvdata->ramp_on_time = temp;
pr_info("%s ramp on time --<%d ms>\n",
__func__, drvdata->ramp_on_time);
}
rc = of_property_read_u32(np, "aw99703,turn-off-ramp", &temp);
if (rc) {
pr_err("Invalid ramp timing ,,turnoff!\n");
} else {
drvdata->ramp_off_time = temp;
pr_info("%s ramp off time --<%d ms>\n",
__func__, drvdata->ramp_off_time);
}
rc = of_property_read_u32(np, "aw99703,pwm-trans-dim", &temp);
if (rc) {
pr_err("Invalid pwm-tarns-dim value!\n");
} else {
drvdata->pwm_trans_dim = temp;
pr_info("%s pwm trnasition dimming --<%d ms>\n",
__func__, drvdata->pwm_trans_dim);
}
rc = of_property_read_u32(np, "aw99703,i2c-trans-dim", &temp);
if (rc) {
pr_err("Invalid i2c-trans-dim value !\n");
} else {
drvdata->i2c_trans_dim = temp;
pr_info("%s i2c transition dimming --<%d ms>\n",
__func__, drvdata->i2c_trans_dim);
}
rc = of_property_read_u32(np, "aw99703,bl-channel", &bl_channel);
if (rc) {
pr_err("Invalid channel setup\n");
} else {
drvdata->channel = bl_channel;
pr_info("%s bl-channel --<%x>\n", __func__, drvdata->channel);
}
rc = of_property_read_u32(np, "aw99703,bl-map", &drvdata->bl_map);
if (rc != 0)
pr_err("%s bl_map not found\n", __func__);
else
pr_info("%s bl_map=%d\n", __func__, drvdata->bl_map);
}
/******************************************************
*
* sys group attribute: reg
*
******************************************************/
static ssize_t aw99703_i2c_reg_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct aw99703_data *aw99703 = dev_get_drvdata(dev);
unsigned int databuf[2] = {0, 0};
if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) {
aw99703_i2c_write(aw99703->client,
(unsigned char)databuf[0],
(unsigned char)databuf[1]);
}
return count;
}
static ssize_t aw99703_i2c_reg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aw99703_data *aw99703 = dev_get_drvdata(dev);
ssize_t len = 0;
unsigned char i = 0;
unsigned char reg_val = 0;
for (i = 0; i < AW99703_REG_MAX; i++) {
if (!(aw99703_reg_access[i]&REG_RD_ACCESS))
continue;
aw99703_i2c_read(aw99703->client, i, &reg_val);
len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x\n",
i, reg_val);
}
return len;
}
static DEVICE_ATTR(reg, 0664, aw99703_i2c_reg_show, aw99703_i2c_reg_store);
static struct attribute *aw99703_attributes[] = {
&dev_attr_reg.attr,
NULL
};
static struct attribute_group aw99703_attribute_group = {
.attrs = aw99703_attributes
};
static int aw99703_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct aw99703_data *drvdata;
#ifdef KERNEL_ABOVE_4_14
struct backlight_device *bl_dev;
struct backlight_properties props;
#endif
int err = 0;
pr_err("%s enter! driver version %s\n", __func__, AW99703_VERSION);
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 aw99703_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;
drvdata->addr = client->addr;
drvdata->brightness = LED_OFF;
drvdata->enable = true;
drvdata->led_dev.default_trigger = "bkl-trigger";
drvdata->led_dev.name = AW99703_LED_DEV;
drvdata->led_dev.brightness_set = aw99703_brightness_set;
drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
mutex_init(&drvdata->lock);
INIT_WORK(&drvdata->work, aw99703_work);
aw99703_get_dt_data(&client->dev, drvdata);
i2c_set_clientdata(client, drvdata);
aw99703_gpio_init(drvdata);
err = aw99703_read_chipid(drvdata);
if (err < 0) {
pr_err("%s : ID idenfy failed\n", __func__);
goto err_init;
}
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_debug("%s: Register led class successful\n", __func__);
}
#ifdef KERNEL_ABOVE_4_14
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW;
props.brightness = MAX_BRIGHTNESS;
props.max_brightness = MAX_BRIGHTNESS;
bl_dev = backlight_device_register(AW99703_NAME, &client->dev,
drvdata, &aw99703_bl_ops, &props);
#endif
g_aw99703_data = drvdata;
aw99703_backlight_init(drvdata);
aw99703_backlight_enable(drvdata);
aw99703_set_brightness(drvdata, MAX_BRIGHTNESS);
err = sysfs_create_group(&client->dev.kobj, &aw99703_attribute_group);
if (err < 0) {
dev_info(&client->dev, "%s error creating sysfs attr files\n",
__func__);
goto err_sysfs;
}
pr_info("%s exit\n", __func__);
return 0;
err_sysfs:
err_init:
kfree(drvdata);
err_out:
return err;
}
static int aw99703_remove(struct i2c_client *client)
{
struct aw99703_data *drvdata = i2c_get_clientdata(client);
led_classdev_unregister(&drvdata->led_dev);
kfree(drvdata);
return 0;
}
static const struct i2c_device_id aw99703_id[] = {
{AW99703_NAME, 0},
{}
};
static struct of_device_id match_table[] = {
{.compatible = "awinic,aw99703-bl",}
};
MODULE_DEVICE_TABLE(i2c, aw99703_id);
static struct i2c_driver aw99703_i2c_driver = {
.probe = aw99703_probe,
.remove = aw99703_remove,
.id_table = aw99703_id,
.driver = {
.name = AW99703_NAME,
.owner = THIS_MODULE,
.of_match_table = match_table,
},
};
module_i2c_driver(aw99703_i2c_driver);
MODULE_DESCRIPTION("Back Light driver for aw99703");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,252 @@
#ifndef _AW99703_REG_H_
#define _AW99703_REG_H_
/*********************************************************
*
* kernel version
*
********************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#define KERNEL_ABOVE_4_14
#endif
/********************************************
* Register List
*******************************************/
#define AW99703_REG_MAX 0x70
#define AW99703_REG_ID 0x00
#define AW99703_REG_SFTRST 0x01
#define AW99703_REG_MODE 0x02
#define AW99703_REG_LEDCUR 0x03
#define AW99703_REG_BSTCTR1 0x04
#define AW99703_REG_BSTCTR2 0x05
#define AW99703_REG_LEDLSB 0x06
#define AW99703_REG_LEDMSB 0x07
#define AW99703_REG_PWM 0x08
#define AW99703_REG_TURNCFG 0x09
#define AW99703_REG_TRANCFG 0x0a
#define AW99703_REG_FLASH 0x0b
#define AW99703_REG_AFHIGH 0x0c
#define AW99703_REG_AFLOW 0x0d
#define AW99703_REG_FLAGS1 0x0e
#define AW99703_REG_FLAGS2 0x0f
#define AW99703_REG_FLAGS3 0x11
#define AW99703_REG_AUTOZERO 0x21
#define AW99703_REG_EMI 0x22
#define AW99703_REG_BSTCTR3 0x23
#define AW99703_REG_BSTCTR4 0x24
#define AW99703_REG_BSTCTR5 0x25
#define AW99703_REG_LEDCFG 0x26
#define AW99703_REG_DITHER 0x27
#define AW99703_REG_PWMMSB 0x28
#define AW99703_REG_PWMLSB 0x29
#define AW99703_REG_TEST 0x31
#define AW99703_REG_FLTDIS 0x33
#define AW99703_REG_EFUSE1 0x40
#define AW99703_REG_EFUSE2 0x41
#define AW99703_REG_EFUSE3 0x42
#define AW99703_REG_EFUSE4 0x43
#define AW99703_REG_EFUSE5 0x44
#define AW99703_REG_EFUSE6 0x45
#define AW99703_REG_EFUSE7 0x46
#define AW99703_REG_EFUSE8 0x47
#define AW99703_REG_EFRUN 0x48
#define AW99703_REG_EFMODE 0x49
#define AW99703_REG_WPRT1 0x67
#define AW99703_REG_WPRT2 0x68
#define AW99703_REG_SCANEN 0x69
/********************************************
* Register Access
*******************************************/
#define REG_NONE_ACCESS 0
#define REG_RD_ACCESS (1 << 0)
#define REG_WR_ACCESS (1 << 1)
const unsigned char aw99703_reg_access[AW99703_REG_MAX] = {
[AW99703_REG_ID] = REG_RD_ACCESS,
[AW99703_REG_SFTRST] = REG_WR_ACCESS,
[AW99703_REG_MODE] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_LEDCUR] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_BSTCTR1] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_BSTCTR2] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_LEDLSB] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_LEDMSB] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_PWM] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_TURNCFG] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_TRANCFG] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_FLASH] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_AFHIGH] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_AFLOW] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW99703_REG_FLAGS1] = REG_RD_ACCESS,
[AW99703_REG_FLAGS2] = REG_RD_ACCESS,
[AW99703_REG_FLAGS3] = REG_RD_ACCESS,
[AW99703_REG_AUTOZERO] = REG_RD_ACCESS,
[AW99703_REG_EMI] = REG_RD_ACCESS,
[AW99703_REG_BSTCTR3] = REG_RD_ACCESS,
[AW99703_REG_BSTCTR4] = REG_RD_ACCESS,
[AW99703_REG_BSTCTR5] = REG_RD_ACCESS,
[AW99703_REG_LEDCFG] = REG_RD_ACCESS,
[AW99703_REG_DITHER] = REG_RD_ACCESS,
[AW99703_REG_PWMMSB] = REG_RD_ACCESS,
[AW99703_REG_PWMLSB] = REG_RD_ACCESS,
[AW99703_REG_TEST] = REG_RD_ACCESS,
[AW99703_REG_FLTDIS] = REG_RD_ACCESS,
[AW99703_REG_EFUSE1] = REG_RD_ACCESS,
[AW99703_REG_EFUSE2] = REG_RD_ACCESS,
[AW99703_REG_EFUSE3] = REG_RD_ACCESS,
[AW99703_REG_EFUSE4] = REG_RD_ACCESS,
[AW99703_REG_EFUSE5] = REG_RD_ACCESS,
[AW99703_REG_EFUSE6] = REG_RD_ACCESS,
[AW99703_REG_EFUSE7] = REG_RD_ACCESS,
[AW99703_REG_EFUSE8] = REG_RD_ACCESS,
[AW99703_REG_EFRUN] = REG_RD_ACCESS,
[AW99703_REG_EFMODE] = REG_RD_ACCESS,
[AW99703_REG_WPRT1] = REG_RD_ACCESS,
[AW99703_REG_WPRT2] = REG_RD_ACCESS,
[AW99703_REG_SCANEN] = REG_RD_ACCESS,
};
#define MAX_BRIGHTNESS (2047)
/******************************************************
* Register Detail
*****************************************************/
/*SFTRST:0x01*/
#define AW99703_SFTRST_MASK (~(1<<0))
#define AW99703_SFTRST_NOT_RST (0<<0)
#define AW99703_SFTRST_RST (1<<0)
/*MODE:0x02*/
#define AW99703_MODE_PDIS_MASK (~(1<<4))
#define AW99703_MODE_PDIS_ENABLE (0<<4)
#define AW99703_MODE_PDIS_DISABLE (1<<4)
#define AW99703_MODE_MAP_MASK (~(1<<2))
#define AW99703_MODE_MAP_EXPONENTIAL (0<<2)
#define AW99703_MODE_MAP_LINEAR (1<<2)
#define AW99703_MODE_WORKMODE_MASK (~(3<<0))
#define AW99703_MODE_WORKMODE_STANDBY (0<<0)
#define AW99703_MODE_WORKMODE_BACKLIGHT (1<<0)
#define AW99703_MODE_WORKMODE_FLASH (2<<0)
/*MODE:0x03*/
#define AW99703_LEDCUR_BLFS_MASK (~(31<<3))
#define AW99703_LEDCUR_CHANNEL_MASK (~(7<<0))
#define AW99703_LEDCUR_CH3_ENABLE (1<<2)
#define AW99703_LEDCUR_CH3_DISABLE (0<<2)
#define AW99703_LEDCUR_CH2_ENABLE (1<<1)
#define AW99703_LEDCUR_CH2_DISABLE (0<<1)
#define AW99703_LEDCUR_CH1_ENABLE (1<<0)
#define AW99703_LEDCUR_CH1_DISABLE (0<<0)
/*BSTCTR1:0x04*/
#define AW99703_BSTCTR1_SF_SFT_MASK (~(3<<6))
#define AW99703_BSTCTR1_SF_SFT_UP20 (1<<6)
#define AW99703_BSTCTR1_SF_SFT_DOWN12 (2<<6)
#define AW99703_BSTCTR1_SF_SFT_DOWN24 (3<<6)
#define AW99703_BSTCTR1_SF_MASK (~(1<<5))
#define AW99703_BSTCTR1_SF_500KHZ (0<<5)
#define AW99703_BSTCTR1_SF_1000KHZ (1<<5)
#define AW99703_BSTCTR1_OVPSEL_MASK (~(7<<2))
#define AW99703_BSTCTR1_OVPSEL_17V (0<<2)
#define AW99703_BSTCTR1_OVPSEL_24V (1<<2)
#define AW99703_BSTCTR1_OVPSEL_31V (2<<2)
#define AW99703_BSTCTR1_OVPSEL_38V (3<<2)
#define AW99703_BSTCTR1_OVPSEL_41P5V (4<<2)
#define AW99703_BSTCTR1_OCPSEL_MASK (~(3<<0))
#define AW99703_BSTCTR1_OCPSEL_0P7A (0<<0)
#define AW99703_BSTCTR1_OCPSEL_1P6A (1<<0)
#define AW99703_BSTCTR1_OCPSEL_2P46A (2<<0)
#define AW99703_BSTCTR1_OCPSEL_3P3A (3<<0)
/*BSTCTR2:0x05*/
#define AW99703_BSTCTR2_AFEN_MASK (~(1<<7))
#define AW99703_BSTCTR2_AFEN_ENABLE (1<<7)
#define AW99703_BSTCTR2_AFEN_DISABLE (0<<7)
#define AW99703_BSTCTR2_IDCTSEL_MASK (~(1<<6))
#define AW99703_BSTCTR2_IDCTSEL_4P7UH (0<<6)
#define AW99703_BSTCTR2_IDCTSEL_10UH (1<<6)
#define AW99703_BSTCTR2_EMISEL_MASK (~(7<<3))
#define AW99703_BSTCTR2_EMISEL_TYPICAL (0<<3)
#define AW99703_BSTCTR2_EMISEL_SLOW1 (1<<3)
#define AW99703_BSTCTR2_EMISEL_SLOW2 (2<<3)
#define AW99703_BSTCTR2_EMISEL_SLOW3 (3<<3)
#define AW99703_BSTCTR2_EMISEL_FAST1 (4<<3)
#define AW99703_BSTCTR2_EMISEL_FAST2 (5<<3)
#define AW99703_BSTCTR2_EMISEL_FAST3 (6<<3)
#define AW99703_BSTCTR2_EMISEL_FAST4 (7<<3)
#define AW99703_BSTCTR2_ADEN_MASK (~(1<<2))
#define AW99703_BSTCTR2_ADEN_ENABLE (1<<2)
#define AW99703_BSTCTR2_ADEN_DISABLE (0<<2)
/*PWM:0x08*/
#define AW99703_PWM_P_SF_MASK (~(3<<6))
#define AW99703_PWM_P_SF_800KHZ (0<<6)
#define AW99703_PWM_P_SF_4MKHZ (1<<6)
#define AW99703_PWM_P_SF_24MKHZ (2<<6)
#define AW99703_PWM_P_ACT_MASK (~(1<<5))
#define AW99703_PWM_P_ACT_HIGH (0<<5)
#define AW99703_PWM_P_ACT_LOW (1<<5)
#define AW99703_PWM_P_HYS_MASK (~(7<<2))
#define AW99703_PWM_P_HYS_NONE (0<<2)
#define AW99703_PWM_P_HYS_1LSB (1<<2)
#define AW99703_PWM_P_HYS_2LSB (2<<2)
#define AW99703_PWM_P_HYS_3LSB (3<<2)
#define AW99703_PWM_P_HYS_4LSB (4<<2)
#define AW99703_PWM_P_HYS_5LSB (5<<2)
#define AW99703_PWM_P_HYS_6LSB (6<<2)
#define AW99703_PWM_P_HYS_7LSB (7<<2)
#define AW99703_PWM_P_FLT_MASK (~(3<<0))
#define AW99703_PWM_P_FLT_NONE (0<<0)
#define AW99703_PWM_P_FLT_100MS (1<<0)
#define AW99703_PWM_P_FLT_150MS (2<<0)
#define AW99703_PWM_P_FLT_200MS (3<<0)
/*TURNCFG:0x09*/
#define AW99703_TURNCFG_ON_TIM_MASK (~(15<<4))
#define AW99703_TURNCFG_OFF_TIM_MASK (~(15<<0))
/*TRANCFG:0x0A*/
#define AW99703_TRANCFG_PWM_TIM_MASK (~(7<<4))
#define AW99703_TRANCFG_I2C_TIM_MASK (~(15<<0))
#define MAX_BRIGHTNESS (2047)
#define AW_READ_CHIPID_RETRIES 5
#define AW_READ_CHIPID_RETRY_DELAY 2
struct aw99703_data {
struct led_classdev led_dev;
struct i2c_client *client;
struct device dev;
struct i2c_adapter *adapter;
unsigned short addr;
struct mutex lock;
struct work_struct work;
enum led_brightness brightness;
bool enable;
unsigned char pwm_cfg;
unsigned char full_scale_current;
bool brt_code_enable;
unsigned short *brt_code_table;
int hwen_gpio;
unsigned int 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;
unsigned int bl_map;
struct backlight_device *bl_dev;
};
#endif