mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2024-11-19 13:27:49 +00:00
175 lines
4.2 KiB
C
175 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// Copyright (c) 2019 MediaTek Inc.
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/spmi.h>
|
|
#include <dt-bindings/spmi/spmi.h>
|
|
|
|
struct mtk_spmi_pmic_debug_data {
|
|
struct mutex lock;
|
|
struct regmap *regmap;
|
|
unsigned int reg_value;
|
|
u8 usid;
|
|
};
|
|
|
|
static struct mtk_spmi_pmic_debug_data *mtk_spmi_pmic_debug[SPMI_MAX_SLAVE_ID];
|
|
|
|
static ssize_t pmic_access_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct mtk_spmi_pmic_debug_data *data = dev_get_drvdata(dev);
|
|
|
|
dev_info(dev, "0x%x\n", data->reg_value);
|
|
return sprintf(buf, "0x%x\n", data->reg_value);
|
|
}
|
|
|
|
static ssize_t pmic_access_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t size)
|
|
{
|
|
struct mtk_spmi_pmic_debug_data *data;
|
|
struct regmap *regmap;
|
|
int ret = 0;
|
|
char *pvalue = NULL, *addr, *val;
|
|
unsigned int reg_val = 0;
|
|
unsigned int reg_adr = 0;
|
|
u8 usid = 0;
|
|
|
|
if (dev) {
|
|
data = dev_get_drvdata(dev);
|
|
if (!data)
|
|
return -ENODEV;
|
|
} else
|
|
return -ENODEV;
|
|
|
|
if (buf != NULL && size != 0) {
|
|
dev_info(dev, "size is %d, buf is %s\n", (int)size, buf);
|
|
|
|
pvalue = (char *)buf;
|
|
addr = strsep(&pvalue, " ");
|
|
val = strsep(&pvalue, " ");
|
|
if (addr)
|
|
ret = kstrtou32(addr, 16, (unsigned int *)®_adr);
|
|
if (reg_adr & 0xF0000) {
|
|
usid = (u8)((reg_adr & 0xF0000) >> 16);
|
|
if (!mtk_spmi_pmic_debug[usid]) {
|
|
data->reg_value = 0;
|
|
dev_info(dev, "invalid slave-%d\n", usid);
|
|
return -ENODEV;
|
|
}
|
|
regmap = mtk_spmi_pmic_debug[usid]->regmap;
|
|
reg_adr &= (0xFFFF);
|
|
} else {
|
|
usid = data->usid;
|
|
regmap = data->regmap;
|
|
}
|
|
mutex_lock(&data->lock);
|
|
|
|
if (val) {
|
|
ret = kstrtou32(val, 16, (unsigned int *)®_val);
|
|
ret = regmap_write(regmap, reg_adr, reg_val);
|
|
} else
|
|
ret = regmap_read(regmap, reg_adr, &data->reg_value);
|
|
|
|
mutex_unlock(&data->lock);
|
|
dev_info(dev, "%s slave-%d PMIC Reg[0x%x]=0x%x!\n",
|
|
(val ? "write" : "read"), usid, reg_adr,
|
|
(val ? reg_val : data->reg_value));
|
|
}
|
|
return size;
|
|
}
|
|
static DEVICE_ATTR_RW(pmic_access);
|
|
|
|
static int mtk_spmi_debug_parse_dt(struct device *dev)
|
|
{
|
|
struct device_node *node;
|
|
int err;
|
|
u32 reg[2] = {0};
|
|
|
|
if (!dev || !dev->of_node)
|
|
return -ENODEV;
|
|
node = dev->of_node;
|
|
err = of_property_read_u32_array(node, "reg", reg, 2);
|
|
if (err) {
|
|
pr_info("%s does not have 'reg' property\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (reg[1] != SPMI_USID) {
|
|
pr_info("%s node contains unsupported 'reg' entry\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (reg[0] >= SPMI_MAX_SLAVE_ID) {
|
|
pr_info("%s invalid usid=%d\n", __func__, reg[0]);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return reg[0];
|
|
}
|
|
|
|
static int mtk_spmi_pmic_debug_probe(struct platform_device *pdev)
|
|
{
|
|
struct mtk_spmi_pmic_debug_data *data;
|
|
int ret = 0, usid = 0;
|
|
|
|
data = devm_kzalloc(&pdev->dev, sizeof(struct mtk_spmi_pmic_debug_data),
|
|
GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
mutex_init(&data->lock);
|
|
data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
|
if (!data->regmap)
|
|
return -ENODEV;
|
|
|
|
platform_set_drvdata(pdev, data);
|
|
|
|
/* Create sysfs entry */
|
|
ret = device_create_file(&pdev->dev, &dev_attr_pmic_access);
|
|
if (ret < 0)
|
|
dev_info(&pdev->dev, "failed to create sysfs file\n");
|
|
usid = mtk_spmi_debug_parse_dt(pdev->dev.parent);
|
|
if (usid >= 0) {
|
|
data->usid = (u8) usid;
|
|
mtk_spmi_pmic_debug[usid] = data;
|
|
}
|
|
dev_info(&pdev->dev, "success to create %s slave-%d sysfs file\n", pdev->name, usid);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mtk_spmi_pmic_debug_remove(struct platform_device *pdev)
|
|
{
|
|
device_remove_file(&pdev->dev, &dev_attr_pmic_access);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id mtk_spmi_pmic_debug_of_match[] = {
|
|
{ .compatible = "mediatek,spmi-pmic-debug", },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mtk_spmi_pmic_debug_of_match);
|
|
|
|
static struct platform_driver mtk_spmi_pmic_debug_driver = {
|
|
.driver = {
|
|
.name = "mtk-spmi-pmic-debug",
|
|
.of_match_table = mtk_spmi_pmic_debug_of_match,
|
|
},
|
|
.probe = mtk_spmi_pmic_debug_probe,
|
|
.remove = mtk_spmi_pmic_debug_remove,
|
|
};
|
|
module_platform_driver(mtk_spmi_pmic_debug_driver);
|
|
|
|
MODULE_AUTHOR("Wen Su <wen.su@mediatek.com>");
|
|
MODULE_AUTHOR("Jeter Chen <jeter.chen@mediatek.com>");
|
|
MODULE_DESCRIPTION("Debug driver for MediaTek SPMI PMIC");
|
|
MODULE_LICENSE("GPL v2");
|