kernel_samsung_a34x-permissive/drivers/misc/mediatek/gate_ic/rt4831a_drv.c
2024-04-28 15:51:13 +02:00

366 lines
10 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include "gate_i2c.h"
#ifdef CONFIG_LEDS_MTK_PWM
#include <leds-mtk-pwm.h>
#define CONFIG_LEDS_BRIGHTNESS_CHANGED
#elif defined CONFIG_LEDS_MTK_I2C
#include <leds-mtk-i2c.h>
#define CONFIG_LEDS_BRIGHTNESS_CHANGED
#endif
/*****************************************************************************
* Define
*****************************************************************************/
#define GATE_I2C_ID_NAME "gate_ic_i2c_rt4831"
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME " %s(%d) :[GATE][I2C] " fmt, __func__, __LINE__
/*****************************************************************************
* Define Register
*****************************************************************************/
#define BACKLIGHT_CONFIG_1 0x02
#define BACKLIGHT_CONFIG_2 0x03
#define BACKLIGHT_BRIGHTNESS_LSB 0x04
#define BACKLIGHT_BRIGHTNESS_MSB 0x05
#define BACKLIGHT_AUTO_FREQ_LOW 0x06
#define BACKLIGHT_AUTO_FREQ_HIGH 0x07
#define BACKLIGHT_ENABLE 0x08
#define FLAGS 0x0F
#define BACKLIGHT_OPTION_1 0x10
#define BACKLIGHT_OPTION_2 0x11
#define BACKLIGHT_SMOOTH 0x14
#define BRIGHTNESS_HIGN_OFFSET 0x3
#define BRIGHTNESS_HIGN_MASK 0xFF
#define BRIGHTNESS_LOW_OFFSET 0x0
#define BRIGHTNESS_LOW_MASK 0x7
#define DISPLAY_BIAS_CONFIGURATION_1 0x09
#define DISPLAY_BIAS_CONFIGURATION_2 0x0A
#define DISPLAY_BIAS_CONFIGURATION_3 0x0B
#define LCM_BIAS 0x0C
#define VPOS_BIAS 0x0D
#define VNEG_BIAS 0x0E
/*****************************************************************************
* GLobal Variable
*****************************************************************************/
static const struct of_device_id _gate_ic_i2c_of_match[] = {
{
.compatible = "mediatek,gate-ic-i2c",
},
};
static struct i2c_client *_gate_ic_i2c_client;
struct gate_ic_client {
struct i2c_client *i2c_client;
struct gpio_desc *pinctrl;
struct device *dev;
bool pwm_enable;
atomic_t gate_ic_power_status;
atomic_t backlight_status;
};
/*****************************************************************************
* Driver Functions
*****************************************************************************/
static void _gate_ic_backlight_enable(void)
{
/*BL enable*/
struct gate_ic_client *gate_client = i2c_get_clientdata(_gate_ic_i2c_client);
pr_info("Backlight enable\n");
if (gate_client->pwm_enable) {
_gate_ic_i2c_write_bytes(BACKLIGHT_CONFIG_1, 0x6B);
} else {
_gate_ic_i2c_write_bytes(BACKLIGHT_CONFIG_1, 0x68);
if (!atomic_read(&gate_client->backlight_status))
_gate_ic_backlight_set(0);
}
_gate_ic_i2c_write_bytes(BACKLIGHT_CONFIG_2, 0x9D);
_gate_ic_i2c_write_bytes(BACKLIGHT_OPTION_1, 0x06);
_gate_ic_i2c_write_bytes(BACKLIGHT_OPTION_2, 0xB7);
/*bias enable*/
_gate_ic_i2c_write_bytes(BACKLIGHT_ENABLE, 0x15);
_gate_ic_i2c_write_bytes(BACKLIGHT_SMOOTH, 0x03);
}
#ifdef CONFIG_LEDS_BRIGHTNESS_CHANGED
int _backlight_changed_event(struct notifier_block *nb, unsigned long event,
void *v)
{
struct led_conf_info *led_conf;
struct gate_ic_client *gate_client = i2c_get_clientdata(_gate_ic_i2c_client);
led_conf = (struct led_conf_info *)v;
switch (event) {
case 1:
if (led_conf->cdev.brightness > 0)
atomic_set(&gate_client->backlight_status, 1);
else
atomic_set(&gate_client->backlight_status, 0);
break;
default:
break;
}
return NOTIFY_DONE;
}
static struct notifier_block leds_init_notifier = {
.notifier_call = _backlight_changed_event,
};
#endif
/*****************************************************************************
* Extern Area
*****************************************************************************/
void _gate_ic_backlight_set(unsigned int hw_level)
{
int level_l, level_h;
struct i2c_client *client = _gate_ic_i2c_client;
char cmd_buf[3] = { 0x00, 0x00, 0x00 };
int ret = 0;
level_h = (hw_level >> BRIGHTNESS_HIGN_OFFSET) & BRIGHTNESS_HIGN_MASK;
level_l = (hw_level >> BRIGHTNESS_LOW_OFFSET) & BRIGHTNESS_LOW_MASK;
cmd_buf[0] = BACKLIGHT_BRIGHTNESS_LSB;
cmd_buf[1] = level_l;
cmd_buf[2] = level_h;
ret = i2c_master_send(client, cmd_buf, 3);
if (ret < 0)
pr_info("ERROR %d!! i2c write data fail 0x%0x, 0x%0x, 0x%0x !!\n",
ret, cmd_buf[0], cmd_buf[1], cmd_buf[2]);
}
EXPORT_SYMBOL_GPL(_gate_ic_backlight_set);
int _gate_ic_i2c_read_bytes(unsigned char addr, unsigned char *returnData)
{
char cmd_buf[2] = { 0x00, 0x00 };
char readData = 0;
int ret = 0;
struct i2c_client *client = _gate_ic_i2c_client;
if (client == NULL) {
pr_info("ERROR!! _gate_ic_i2c_client is null\n");
return 0;
}
cmd_buf[0] = addr;
ret = i2c_master_send(client, &cmd_buf[0], 1);
ret = i2c_master_recv(client, &cmd_buf[1], 1);
if (ret < 0)
pr_info("ERROR %d!! i2c read data 0x%0x fail !!\n", ret, addr);
readData = cmd_buf[1];
*returnData = readData;
return ret;
}
EXPORT_SYMBOL_GPL(_gate_ic_i2c_read_bytes);
int _gate_ic_i2c_write_bytes(unsigned char addr, unsigned char value)
{
int ret = 0;
struct i2c_client *client = _gate_ic_i2c_client;
char write_data[2] = { 0 };
if (client == NULL) {
pr_info("ERROR!! _gate_ic_i2c_client is null\n");
return 0;
}
write_data[0] = addr;
write_data[1] = value;
ret = i2c_master_send(client, write_data, 2);
if (ret < 0)
pr_info("ERROR %d!! i2c write data fail 0x%0x, 0x%0x !!\n",
ret, addr, value);
return ret;
}
EXPORT_SYMBOL_GPL(_gate_ic_i2c_write_bytes);
void _gate_ic_Power_on(void)
{
struct gate_ic_client *gate_client = i2c_get_clientdata(_gate_ic_i2c_client);
pr_info("Status: %d, %d\n",
atomic_read(&gate_client->gate_ic_power_status),
atomic_read(&gate_client->backlight_status));
if (IS_ERR(gate_client->pinctrl)) {
pr_info("ERROR!! pinctrl is error!\n");
} else if (!atomic_read(&gate_client->gate_ic_power_status)) {
gpiod_set_value(gate_client->pinctrl, 1);
devm_gpiod_put(gate_client->dev, gate_client->pinctrl);
atomic_set(&gate_client->gate_ic_power_status, 1);
_gate_ic_backlight_enable();
}
}
EXPORT_SYMBOL_GPL(_gate_ic_Power_on);
void _gate_ic_Power_off(void)
{
struct gate_ic_client *gate_client = i2c_get_clientdata(_gate_ic_i2c_client);
pr_info("Status: %d, %d\n",
atomic_read(&gate_client->gate_ic_power_status),
atomic_read(&gate_client->backlight_status));
if (IS_ERR(gate_client->pinctrl)) {
pr_info("ERROR!! pinctrl is error!\n");
} else if (atomic_read(&gate_client->gate_ic_power_status) &&
!atomic_read(&gate_client->backlight_status)) {
gpiod_set_value(gate_client->pinctrl, 0);
devm_gpiod_put(gate_client->dev, gate_client->pinctrl);
atomic_set(&gate_client->gate_ic_power_status, 0);
}
}
EXPORT_SYMBOL_GPL(_gate_ic_Power_off);
void _gate_ic_i2c_panel_bias_enable(unsigned int power_status)
{
pr_info("Panel bias enable\n");
if (power_status) {
_gate_ic_i2c_write_bytes(DISPLAY_BIAS_CONFIGURATION_2, 0x11);
_gate_ic_i2c_write_bytes(DISPLAY_BIAS_CONFIGURATION_3, 0x00);
/*set bias to 5.4v*/
_gate_ic_i2c_write_bytes(LCM_BIAS, 0x24);
_gate_ic_i2c_write_bytes(VPOS_BIAS, 0x1c);
_gate_ic_i2c_write_bytes(VNEG_BIAS, 0x1c);
/* set dsv FPWM mode */
_gate_ic_i2c_write_bytes(0xF0, 0x69);
_gate_ic_i2c_write_bytes(0xB1, 0x6c);
/*bias enable*/
_gate_ic_i2c_write_bytes(DISPLAY_BIAS_CONFIGURATION_1, 0x9e);
} else {
_gate_ic_i2c_write_bytes(DISPLAY_BIAS_CONFIGURATION_1, 0x18);
}
}
EXPORT_SYMBOL_GPL(_gate_ic_i2c_panel_bias_enable);
/*****************************************************************************
* Function
*****************************************************************************/
static int _gate_ic_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct gate_ic_client *gate_client;
struct device *dev = &client->dev;
int status;
int pwm_enable;
pr_info("%s NT: info==>name=%s addr=0x%x\n",
__func__, client->name, client->addr);
gate_client = devm_kzalloc(&client->dev, sizeof(struct gate_ic_client), GFP_KERNEL);
if (!gate_client)
return -ENOMEM;
gate_client->dev = &client->dev;
gate_client->i2c_client = client;
gate_client->pinctrl = devm_gpiod_get(&client->dev, "gate-power",
GPIOD_OUT_HIGH);
if (IS_ERR(gate_client->pinctrl)) {
status = PTR_ERR(gate_client->pinctrl);
pr_info("ERROR!! Failed to enable gpio: %d\n", status);
return status;
}
i2c_set_clientdata(client, gate_client);
_gate_ic_i2c_client = client;
atomic_set(&gate_client->gate_ic_power_status, 1);
atomic_set(&gate_client->gate_ic_power_status, 1);
status = of_property_read_u32(dev->of_node, "pwm-enable", &pwm_enable);
if (status) {
gate_client->pwm_enable = 0;
pr_info("ERROR!! Failed to get pwm-enable, use default value 0");
} else {
gate_client->pwm_enable = pwm_enable;
}
#ifdef CONFIG_LEDS_BRIGHTNESS_CHANGED
mtk_leds_register_notifier(&leds_init_notifier);
#endif
pr_info("Probe success! pwm-enable is %d", pwm_enable);
return 0;
}
static int _gate_ic_i2c_remove(struct i2c_client *client)
{
struct gate_ic_client *gate_client;
pr_info("Gate ic remove\n");
gate_client = i2c_get_clientdata(client);
i2c_unregister_device(client);
kfree(gate_client);
gate_client = NULL;
_gate_ic_i2c_client = NULL;
i2c_unregister_device(client);
#ifdef CONFIG_LEDS_BRIGHTNESS_CHANGED
mtk_leds_unregister_notifier(&leds_init_notifier);
#endif
return 0;
}
/*****************************************************************************
* Data Structure
*****************************************************************************/
static const struct i2c_device_id _gate_ic_i2c_id[] = {
{GATE_I2C_ID_NAME, 0},
{}
};
static struct i2c_driver _gate_ic_i2c_driver = {
.id_table = _gate_ic_i2c_id,
.probe = _gate_ic_i2c_probe,
.remove = _gate_ic_i2c_remove,
.driver = {
.owner = THIS_MODULE,
.name = GATE_I2C_ID_NAME,
.of_match_table = _gate_ic_i2c_of_match,
},
};
module_i2c_driver(_gate_ic_i2c_driver);
MODULE_AUTHOR("Mediatek Corporation");
MODULE_DESCRIPTION("MTK RT4831 I2C Driver");
MODULE_LICENSE("GPL");