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

647 lines
16 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 MediaTek Inc.
*/
#include <linux/i2c.h>
#include <linux/init.h> /* For init/exit macros */
#include <linux/module.h> /* For MODULE_ marcros */
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#endif
#include "bq24196.h"
/**********************************************************
*
* [I2C Slave Setting]
*
*********************************************************/
#define bq24196_SLAVE_ADDR_WRITE 0xD6
#define bq24196_SLAVE_ADDR_READ 0xD7
#ifdef CONFIG_OF
static const struct of_device_id bq24196_id[] = {
{.compatible = "ti,bq24196"}, {},
};
MODULE_DEVICE_TABLE(of, bq24196_id);
#endif
static struct i2c_client *new_client;
static const struct i2c_device_id bq24196_i2c_id[] = {{"bq24196", 0}, {} };
kal_bool chargin_hw_init_done = KAL_FALSE;
static int bq24196_driver_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static void bq24196_shutdown(struct i2c_client *client)
{
pr_notice("[%s] driver shutdown\n", __func__);
bq24196_set_chg_config(0x0);
}
static struct i2c_driver bq24196_driver = {
.driver = {
.name = "bq24196",
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(bq24196_id),
#endif
},
.probe = bq24196_driver_probe,
.id_table = bq24196_i2c_id,
.shutdown = bq24196_shutdown,
};
/**********************************************************
*
*[Global Variable]
*
*********************************************************/
#define bq24196_REG_NUM 11
unsigned char bq24196_reg[bq24196_REG_NUM] = {0};
static DEFINE_MUTEX(bq24196_i2c_access);
/**********************************************************
*
* [I2C Function For Read/Write bq24196]
*
*********************************************************/
int bq24196_read_byte(unsigned char cmd, unsigned char *returnData)
{
char readData = 0;
int ret = 0;
struct i2c_msg msg[2];
struct i2c_adapter *adap = new_client->adapter;
mutex_lock(&bq24196_i2c_access);
msg[0].addr = new_client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &cmd;
msg[1].addr = new_client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 1;
msg[1].buf = &readData;
ret = i2c_transfer(adap, msg, 2);
if (ret < 0) {
mutex_unlock(&bq24196_i2c_access);
return 0;
}
*returnData = readData;
mutex_unlock(&bq24196_i2c_access);
return 1;
}
int bq24196_write_byte(unsigned char cmd, unsigned char writeData)
{
char write_data[2] = {0};
int ret = 0;
struct i2c_msg msg;
struct i2c_adapter *adap = new_client->adapter;
mutex_lock(&bq24196_i2c_access);
write_data[0] = cmd;
write_data[1] = writeData;
msg.addr = new_client->addr;
msg.flags = 0;
msg.len = 2;
msg.buf = (char *)write_data;
ret = i2c_transfer(adap, &msg, 1);
if (ret < 0) {
mutex_unlock(&bq24196_i2c_access);
return 0;
}
mutex_unlock(&bq24196_i2c_access);
return 1;
}
/**********************************************************
*
* [Read / Write Function]
*
*********************************************************/
unsigned int bq24196_read_interface(unsigned char RegNum, unsigned char *val,
unsigned char MASK, unsigned char SHIFT)
{
unsigned char bq24196_reg = 0;
int ret = 0;
pr_debug("--------------------------------------------------\n");
ret = bq24196_read_byte(RegNum, &bq24196_reg);
pr_debug("[%s] Reg[%x]=0x%x\n", RegNum, __func__,
bq24196_reg);
bq24196_reg &= (MASK << SHIFT);
*val = (bq24196_reg >> SHIFT);
pr_debug("[%s] val=0x%x\n", __func__, *val);
return ret;
}
unsigned int bq24196_config_interface(unsigned char RegNum, unsigned char val,
unsigned char MASK, unsigned char SHIFT)
{
unsigned char bq24196_reg = 0;
int ret = 0;
pr_debug("--------------------------------------------------\n");
ret = bq24196_read_byte(RegNum, &bq24196_reg);
pr_debug("[%s] Reg[%x]=0x%x\n", RegNum, __func__
bq24196_reg);
bq24196_reg &= ~(MASK << SHIFT);
bq24196_reg |= (val << SHIFT);
ret = bq24196_write_byte(RegNum, bq24196_reg);
pr_debug("[%s] write Reg[%x]=0x%x\n", RegNum,
__func__, bq24196_reg);
return ret;
}
/**********************************************************
*
* [Internal Function]
*
*********************************************************/
/* CON0---------------------------------------------------- */
void bq24196_set_en_hiz(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON0),
(unsigned char)(val),
(unsigned char)(CON0_EN_HIZ_MASK),
(unsigned char)(CON0_EN_HIZ_SHIFT));
}
void bq24196_set_vindpm(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON0),
(unsigned char)(val),
(unsigned char)(CON0_VINDPM_MASK),
(unsigned char)(CON0_VINDPM_SHIFT));
}
void bq24196_set_iinlim(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON0),
(unsigned char)(val),
(unsigned char)(CON0_IINLIM_MASK),
(unsigned char)(CON0_IINLIM_SHIFT));
}
/* CON1---------------------------------------------------- */
void bq24196_set_reg_rst(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON1),
(unsigned char)(val),
(unsigned char)(CON1_REG_RST_MASK),
(unsigned char)(CON1_REG_RST_SHIFT));
}
void bq24196_set_wdt_rst(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON1),
(unsigned char)(val),
(unsigned char)(CON1_WDT_RST_MASK),
(unsigned char)(CON1_WDT_RST_SHIFT));
}
void bq24196_set_chg_config(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON1),
(unsigned char)(val),
(unsigned char)(CON1_CHG_CONFIG_MASK),
(unsigned char)(CON1_CHG_CONFIG_SHIFT));
}
void bq24196_set_sys_min(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON1),
(unsigned char)(val),
(unsigned char)(CON1_SYS_MIN_MASK),
(unsigned char)(CON1_SYS_MIN_SHIFT));
}
void bq24196_set_boost_lim(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON1),
(unsigned char)(val),
(unsigned char)(CON1_BOOST_LIM_MASK),
(unsigned char)(CON1_BOOST_LIM_SHIFT));
}
/* CON2---------------------------------------------------- */
void bq24196_set_ichg(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON2),
(unsigned char)(val),
(unsigned char)(CON2_ICHG_MASK),
(unsigned char)(CON2_ICHG_SHIFT));
}
void bq24196_set_force_20pct(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON2),
(unsigned char)(val),
(unsigned char)(CON2_FORCE_20PCT_MASK),
(unsigned char)(CON2_FORCE_20PCT_SHIFT));
}
/* CON3---------------------------------------------------- */
void bq24196_set_iprechg(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON3),
(unsigned char)(val),
(unsigned char)(CON3_IPRECHG_MASK),
(unsigned char)(CON3_IPRECHG_SHIFT));
}
void bq24196_set_iterm(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON3),
(unsigned char)(val),
(unsigned char)(CON3_ITERM_MASK),
(unsigned char)(CON3_ITERM_SHIFT));
}
/* CON4---------------------------------------------------- */
void bq24196_set_vreg(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON4),
(unsigned char)(val),
(unsigned char)(CON4_VREG_MASK),
(unsigned char)(CON4_VREG_SHIFT));
}
void bq24196_set_batlowv(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON4),
(unsigned char)(val),
(unsigned char)(CON4_BATLOWV_MASK),
(unsigned char)(CON4_BATLOWV_SHIFT));
}
void bq24196_set_vrechg(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON4),
(unsigned char)(val),
(unsigned char)(CON4_VRECHG_MASK),
(unsigned char)(CON4_VRECHG_SHIFT));
}
/* CON5---------------------------------------------------- */
void bq24196_set_en_term(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON5),
(unsigned char)(val),
(unsigned char)(CON5_EN_TERM_MASK),
(unsigned char)(CON5_EN_TERM_SHIFT));
}
void bq24196_set_term_stat(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON5),
(unsigned char)(val),
(unsigned char)(CON5_TERM_STAT_MASK),
(unsigned char)(CON5_TERM_STAT_SHIFT));
}
void bq24196_set_watchdog(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON5),
(unsigned char)(val),
(unsigned char)(CON5_WATCHDOG_MASK),
(unsigned char)(CON5_WATCHDOG_SHIFT));
}
void bq24196_set_en_timer(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON5),
(unsigned char)(val),
(unsigned char)(CON5_EN_TIMER_MASK),
(unsigned char)(CON5_EN_TIMER_SHIFT));
}
void bq24196_set_chg_timer(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON5),
(unsigned char)(val),
(unsigned char)(CON5_CHG_TIMER_MASK),
(unsigned char)(CON5_CHG_TIMER_SHIFT));
}
/* CON6---------------------------------------------------- */
void bq24196_set_treg(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON6),
(unsigned char)(val),
(unsigned char)(CON6_TREG_MASK),
(unsigned char)(CON6_TREG_SHIFT));
}
/* CON7---------------------------------------------------- */
void bq24196_set_tmr2x_en(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON7),
(unsigned char)(val),
(unsigned char)(CON7_TMR2X_EN_MASK),
(unsigned char)(CON7_TMR2X_EN_SHIFT));
}
void bq24196_set_batfet_disable(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface(
(unsigned char)(bq24196_CON7), (unsigned char)(val),
(unsigned char)(CON7_BATFET_Disable_MASK),
(unsigned char)(CON7_BATFET_Disable_SHIFT));
}
void bq24196_set_int_mask(unsigned int val)
{
unsigned int ret = 0;
ret = bq24196_config_interface((unsigned char)(bq24196_CON7),
(unsigned char)(val),
(unsigned char)(CON7_INT_MASK_MASK),
(unsigned char)(CON7_INT_MASK_SHIFT));
}
/* CON8---------------------------------------------------- */
unsigned int bq24196_get_system_status(void)
{
unsigned int ret = 0;
unsigned char val = 0;
ret = bq24196_read_interface((unsigned char)(bq24196_CON8), (&val),
(unsigned char)(0xFF),
(unsigned char)(0x0));
return val;
}
unsigned int bq24196_get_vbus_stat(void)
{
unsigned int ret = 0;
unsigned char val = 0;
ret = bq24196_read_interface((unsigned char)(bq24196_CON8), (&val),
(unsigned char)(CON8_VBUS_STAT_MASK),
(unsigned char)(CON8_VBUS_STAT_SHIFT));
return val;
}
unsigned int bq24196_get_chrg_stat(void)
{
unsigned int ret = 0;
unsigned char val = 0;
ret = bq24196_read_interface((unsigned char)(bq24196_CON8), (&val),
(unsigned char)(CON8_CHRG_STAT_MASK),
(unsigned char)(CON8_CHRG_STAT_SHIFT));
return val;
}
unsigned int bq24196_get_vsys_stat(void)
{
unsigned int ret = 0;
unsigned char val = 0;
ret = bq24196_read_interface((unsigned char)(bq24196_CON8), (&val),
(unsigned char)(CON8_VSYS_STAT_MASK),
(unsigned char)(CON8_VSYS_STAT_SHIFT));
return val;
}
/**********************************************************
*
* [Internal Function]
*
*********************************************************/
void bq24196_dump_register(void)
{
int i = 0;
pr_debug("[bq24196] ");
for (i = 0; i < bq24196_REG_NUM; i++) {
bq24196_read_byte(i, &bq24196_reg[i]);
pr_debug("[0x%x]=0x%x ", i, bq24196_reg[i]);
}
pr_debug("\n");
}
static int bq24196_driver_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
pr_debug("[%s]\n", __func__);
new_client = client;
/* --------------------- */
/*bq24196_hw_component_detect();*/
bq24196_dump_register();
chargin_hw_init_done = KAL_TRUE;
return 0;
}
/**********************************************************
*
* [platform_driver API]
*
*********************************************************/
unsigned char g_reg_value_bq24196;
static ssize_t show_bq24196_access(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_debug("[%s] 0x%x\n", __func__, g_reg_value_bq24196);
return sprintf(buf, "%u\n", g_reg_value_bq24196);
}
static ssize_t store_bq24196_access(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int ret = 0;
char *pvalue = NULL, *addr, *val;
unsigned int reg_value = 0;
unsigned int reg_address = 0;
pr_debug("[%s]\n", __func__);
if (buf != NULL && size != 0) {
pr_debug("[%s] buf is %s and size is %zu\n",
__func__, buf, size);
/*reg_address = kstrtoul(buf, 16, &pvalue);*/
pvalue = (char *)buf;
if (size > 3) {
addr = strsep(&pvalue, " ");
ret = kstrtou32(addr, 16, (unsigned int *)&reg_address);
} else
ret = kstrtou32(pvalue, 16,
(unsigned int *)&reg_address);
if (size > 3) {
val = strsep(&pvalue, " ");
ret = kstrtou32(val, 16, (unsigned int *)&reg_value);
pr_debug(
"[%s] write bq24196 reg 0x%x with value 0x%x !\n",
__func__, reg_address, reg_value);
ret = bq24196_config_interface(reg_address, reg_value,
0xFF, 0x0);
} else {
ret = bq24196_read_interface(
reg_address, &g_reg_value_bq24196, 0xFF, 0x0);
pr_debug(
"[%s] read bq24196 reg 0x%x with value 0x%x !\n",
__func__, reg_address, g_reg_value_bq24196);
pr_debug(
"[%s] Please use \"cat bq24196_access\" to get value\r\n",
__func__);
}
}
return size;
}
static DEVICE_ATTR(bq24196_access, 0664, show_bq24196_access,
store_bq24196_access);
static int bq24196_user_space_probe(struct platform_device *dev)
{
int ret_device_file = 0;
pr_notice("******** %s!! ********\n", __func__);
ret_device_file =
device_create_file(&(dev->dev), &dev_attr_bq24196_access);
return 0;
}
struct platform_device bq24196_user_space_device = {
.name = "bq24196-user", .id = -1,
};
static struct platform_driver bq24196_user_space_driver = {
.probe = bq24196_user_space_probe,
.driver = {
.name = "bq24196-user",
},
};
static int __init bq24196_init(void)
{
int ret = 0;
pr_notice("[%s] init start\n", __func__);
#ifndef CONFIG_OF
i2c_register_board_info(bq24196_BUSNUM, &i2c_bq24196, 1);
#endif
if (i2c_add_driver(&bq24196_driver) != 0)
pr_notice(
"[%s] failed to register bq24196 i2c driver.\n",
__func__);
else
pr_notice(
"[%s] Success to register bq24196 i2c driver.\n",
__func__);
/*bq24196 user space access interface*/
ret = platform_device_register(&bq24196_user_space_device);
if (ret) {
pr_notice("****[%s] Unable to device register(%d)\n",
__func__, ret);
return ret;
}
ret = platform_driver_register(&bq24196_user_space_driver);
if (ret) {
pr_notice("****[%s] Unable to register driver (%d)\n",
__func__, ret);
return ret;
}
return 0;
}
static void __exit bq24196_exit(void)
{
i2c_del_driver(&bq24196_driver);
}
// module_init(bq24196_init);
// module_exit(bq24196_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("I2C bq24196 Driver");
MODULE_AUTHOR("YT Lee<yt.lee@mediatek.com>");