kernel_samsung_a34x-permissive/drivers/misc/mediatek/pmic/extbuck/mt6311-i2c.c

390 lines
8.7 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <mt-plat/upmu_common.h>
#include "mt6311-i2c.h"
/*
* Global Variable
*/
/* mt6311 i2c device for mt6311 dirver */
static struct i2c_client *new_client;
static const struct i2c_device_id mt6311_i2c_id[] = {
{"mt6311", 0},
{}
};
static const struct of_device_id mt6311_of_ids[] = {
{.compatible = "mediatek,vproc_buck"},
{},
};
static DEFINE_MUTEX(mt6311_i2c_access);
static int g_mt6311_driver_ready;
static int g_mt6311_hw_exist;
static unsigned char is_mt6311_checked;
/*
* Exported API
*/
int is_mt6311_sw_ready(void)
{
return g_mt6311_driver_ready;
}
int is_mt6311_exist(void)
{
if (is_mt6311_checked == 0) {
#if defined(CONFIG_MTK_PMIC_CHIP_MT6356)
/* get the MT6311 status which is recorded in
* MT6356 register at Preloader
*/
pmic_read_interface(MT6356_TOP_MDB_CONF0,
&g_mt6311_hw_exist, 0x1, 15);
#endif
is_mt6311_checked = 1;
}
return g_mt6311_hw_exist;
}
/*
* Internal Function
*/
static int mt6311_read_device(
unsigned char addr, unsigned int len, unsigned char *data)
{
return i2c_smbus_read_i2c_block_data(new_client, addr, len, data);
}
static int mt6311_write_device(
unsigned char addr, unsigned int len, unsigned char *data)
{
return i2c_smbus_write_i2c_block_data(new_client, addr, len, data);
}
/*
* MT6311 read/write API
*/
int mt6311_read_byte(unsigned char addr, unsigned char *data)
{
int ret = 0;
mutex_lock(&mt6311_i2c_access);
ret = mt6311_read_device(addr, 1, data);
mutex_unlock(&mt6311_i2c_access);
if (ret < 0) {
pr_notice(MT6311TAG "read Reg[0x%x] fail, ret = %d\n"
, addr, ret);
return ret;
}
return 0;
}
int mt6311_write_byte(unsigned char addr, unsigned char data)
{
int ret = 0;
mutex_lock(&mt6311_i2c_access);
ret = mt6311_write_device(addr, 1, &data);
mutex_unlock(&mt6311_i2c_access);
if (ret < 0) {
pr_notice(MT6311TAG "write Reg[0x%x]=0x%x fail, ret = %d\n"
, addr, data, ret);
return ret;
}
return 0;
}
int mt6311_assign_bit(unsigned char reg, unsigned char mask, unsigned char data)
{
unsigned char tmp = 0;
unsigned char regval = 0;
int ret = 0;
mutex_lock(&mt6311_i2c_access);
ret = mt6311_read_device(reg, 1, &regval);
if (ret < 0) {
pr_notice(MT6311TAG "[%s] read fail(ret=%d), Reg[0x%x] data=0x%x, mask=0x%x\n"
, __func__, ret, reg, data, mask);
goto OUT_ASSIGN;
}
tmp = ((regval & 0xff) & ~mask);
tmp |= (data & mask);
ret = mt6311_write_device(reg, 1, &tmp);
if (ret < 0) {
pr_notice(MT6311TAG "[%s] assign bit fail(ret=%d), Reg[0x%x] data=0x%x, mask=0x%x\n"
, __func__, ret, reg, data, mask);
goto OUT_ASSIGN;
}
OUT_ASSIGN:
mutex_unlock(&mt6311_i2c_access);
return ret;
}
int mt6311_read_interface(unsigned char reg, unsigned char *data,
unsigned char mask, unsigned char shift)
{
unsigned char tmp = 0;
unsigned char regval = 0;
int ret = 0;
mutex_lock(&mt6311_i2c_access);
ret = mt6311_read_device(reg, 1, &regval);
tmp = regval;
if (ret < 0) {
pr_notice(MT6311TAG "[%s] read fail(ret=%d), Reg[0x%x], mask=0x%x, shift=%d\n"
, __func__, ret, reg, mask, shift);
goto OUT_ASSIGN;
}
tmp &= (mask << shift);
*data = (tmp >> shift);
OUT_ASSIGN:
mutex_unlock(&mt6311_i2c_access);
return ret;
}
int mt6311_config_interface(unsigned char reg, unsigned char data,
unsigned char mask, unsigned char shift)
{
unsigned char tmp = 0;
unsigned char regval = 0;
int ret = 0;
mutex_lock(&mt6311_i2c_access);
ret = mt6311_read_device(reg, 1, &regval);
tmp = regval;
if (ret < 0) {
pr_notice(MT6311TAG "[%s] read fail(ret=%d), Reg[0x%x] data=0x%x, mask=0x%x, shift=%d\n"
, __func__, ret, reg, data, mask, shift);
goto OUT_ASSIGN;
}
tmp &= ~(mask << shift);
tmp |= (data << shift);
ret = mt6311_write_device(reg, 1, &tmp);
if (ret < 0) {
pr_notice("[%s] write fail(ret=%d), Reg[0x%x] data=0x%x, mask=0x%x, shift=%d\n"
, __func__, ret, reg, data, mask, shift);
goto OUT_ASSIGN;
}
OUT_ASSIGN:
mutex_unlock(&mt6311_i2c_access);
return ret;
}
static int mt6311_check_id(void)
{
int ret = 0;
unsigned char data = 0;
ret = mt6311_read_device(MT6311_CID, 1, &data);
if (ret < 0) {
/* MT6311 IO fail */
pr_notice(MT6311TAG "MT6311 check id fail\n");
return -EIO;
}
if (data != MT6311_CID_CODE) {
/*MT6311 CID(0x%02x) not match */
pr_notice(MT6311TAG "MT6311 id(0x%x) error\n", data);
return -EINVAL;
}
return 0;
}
static int mt6311_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
MT6311LOG("MT6311 probe\n"); /*mt6311_probe*/
new_client = client;
ret = mt6311_check_id();
if (ret < 0)
return ret;
g_mt6311_hw_exist = 1;
#if 0
/* initial setting */
#endif
#ifdef IPIMB_MT6311
pr_notice(MT6311TAG "regulator not support for SSPM\n");
return 0;
#else
ret = mt6311_regulator_init(&client->dev);
if (ret < 0) {
/*mt6311_probe regulator init fail*/
MT6311LOG("MT6311 regulator init fail\n");
return -EINVAL;
}
g_mt6311_driver_ready = 1;
MT6311LOG("MT6311 probe done\n"); /*mt6311_probe --OK!!--*/
return 0;
#endif
}
static int mt6311_i2c_remove(struct i2c_client *client)
{
#ifdef IPIMB_MT6311
pr_notice(MT6311TAG "regulator not support for SSPM\n");
#else
mt6311_regulator_deinit();
#endif
return 0;
}
static struct i2c_driver mt6311_driver = {
.driver = {
.name = "mt6311",
.of_match_table = of_match_ptr(mt6311_of_ids),
},
.probe = mt6311_i2c_probe,
.remove = mt6311_i2c_remove,
.id_table = mt6311_i2c_id,
};
/*
* mt6311_access
*/
static unsigned char g_reg_value_mt6311;
static ssize_t show_mt6311_access(
struct device *dev, struct device_attribute *attr, char *buf)
{
pr_notice(MT6311TAG "[%s] 0x%x\n", __func__, g_reg_value_mt6311);
return sprintf(buf, "0x%x\n", g_reg_value_mt6311);
}
static ssize_t store_mt6311_access(
struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
#ifdef IPIMB_MT6311
pr_notice(MT6311TAG "mt6311_access not support for SSPM\n");
return size;
#else
int ret;
char *pvalue = NULL, *addr, *val;
unsigned int reg_value = 0;
unsigned int reg_address = 0;
pr_notice(MT6311TAG "[%s]\n", __func__);
if (buf != NULL && size != 0) {
pr_notice(MT6311TAG "[%s] size is %d, buf is %s\n"
, __func__, (int)size, buf);
pvalue = (char *)buf;
addr = strsep(&pvalue, " ");
val = strsep(&pvalue, " ");
if (addr)
ret = kstrtou32(addr, 16, (unsigned int *)&reg_address);
if (val) {
ret = kstrtou32(val, 16, (unsigned int *)&reg_value);
pr_notice(MT6311TAG "[%s] write mt6311 reg 0x%x with value 0x%x!\n"
, __func__, reg_address, reg_value);
ret = mt6311_config_interface(reg_address
, reg_value, 0xFF, 0x0);
} else {
ret = mt6311_read_interface(reg_address
, &g_reg_value_mt6311, 0xFF, 0x0);
pr_notice(MT6311TAG "[%s] read mt6311 reg 0x%x with value 0x%x !\n"
, __func__, reg_address, g_reg_value_mt6311);
pr_notice(MT6311TAG "[%s] use \"cat mt6311_access\" to get value\n"
, __func__);
}
}
return size;
#endif
}
/*664*/
static DEVICE_ATTR(mt6311_access
, 0664, show_mt6311_access, store_mt6311_access);
/*
* mt6311_user_space_probe
*/
static int mt6311_user_space_probe(struct platform_device *dev)
{
int ret_device_file = 0;
ret_device_file = device_create_file(&(dev->dev)
, &dev_attr_mt6311_access);
return 0;
}
static struct platform_device mt6311_user_space_device = {
.name = "mt6311-user",
.id = -1,
};
static struct platform_driver mt6311_user_space_driver = {
.probe = mt6311_user_space_probe,
.driver = {
.name = "mt6311-user",
},
};
static int __init mt6311_init(void)
{
int ret = 0;
/* MT6311 i2c driver register */
#ifdef IPIMB_MT6311
pr_notice(MT6311TAG "Kernel driver not support for SSPM\n");
#else
ret = i2c_add_driver(&mt6311_driver);
if (ret != 0) {
pr_notice(MT6311TAG "failed to register mt6311 i2c driver\n");
return ret;
}
MT6311LOG("MT6311 i2c driver probe done\n");
#endif
if (is_mt6311_exist()) {
ret = platform_device_register(&mt6311_user_space_device);
if (ret)
pr_notice(MT6311TAG "failed to create mt6311_access file(device register fail)\n"
);
ret = platform_driver_register(&mt6311_user_space_driver);
if (ret)
pr_notice(MT6311TAG "failed to create mt6311_access file(driver register fail)\n"
);
MT6311LOG("MT6311 user space driver probe done\n");
} else {
MT6311LOG("MT6311 not exist!, user space driver not probe\n");
}
return ret;
}
static void __exit mt6311_exit(void)
{
i2c_del_driver(&mt6311_driver);
}
module_init(mt6311_init);
module_exit(mt6311_exit);
MODULE_AUTHOR("Jeter Chen");
MODULE_DESCRIPTION("MT6311 Device Driver");
MODULE_LICENSE("GPL");