diff --git a/drivers/backlight/aw99703/Android.mk b/drivers/backlight/aw99703/Android.mk new file mode 100644 index 000000000000..dbc467d05587 --- /dev/null +++ b/drivers/backlight/aw99703/Android.mk @@ -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 diff --git a/drivers/backlight/aw99703/Kbuild b/drivers/backlight/aw99703/Kbuild new file mode 100644 index 000000000000..0772225e16dc --- /dev/null +++ b/drivers/backlight/aw99703/Kbuild @@ -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 diff --git a/drivers/backlight/aw99703/Makefile b/drivers/backlight/aw99703/Makefile new file mode 100644 index 000000000000..123bea3f132d --- /dev/null +++ b/drivers/backlight/aw99703/Makefile @@ -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 diff --git a/drivers/backlight/aw99703/leds_aw99703.c b/drivers/backlight/aw99703/leds_aw99703.c new file mode 100644 index 000000000000..48ad7bc9e0f3 --- /dev/null +++ b/drivers/backlight/aw99703/leds_aw99703.c @@ -0,0 +1,719 @@ +/* +* aw99703.c aw99703 backlight module +* +* Version: v1.0.3 +* +* Copyright (c) 2019 AWINIC Technology CO., LTD +* +* Author: Joseph +* +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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, ®_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]®_RD_ACCESS)) + continue; + aw99703_i2c_read(aw99703->client, i, ®_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"); diff --git a/drivers/backlight/aw99703/leds_aw99703.h b/drivers/backlight/aw99703/leds_aw99703.h new file mode 100644 index 000000000000..e529ff3cecca --- /dev/null +++ b/drivers/backlight/aw99703/leds_aw99703.h @@ -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