blob: 50aea8ea358dfe2f93c9cff95a75911c01686749 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2019 MediaTek Inc.
4 * Author: Argus Lin <argus.lin@mediatek.com>
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/of_platform.h>
10#include <linux/regmap.h>
11#include <linux/spmi.h>
12
13struct mtk_spmi_pmic_data {
14 unsigned int max_register;
15 unsigned int check_reg;
16};
17
18#define MTK_SPMI_PMIC_DATA(chip, _max_register, _check_reg) \
19static const struct mtk_spmi_pmic_data chip##_data = \
20{ \
21 .max_register = _max_register, \
22 .check_reg = _check_reg, \
23} \
24
25MTK_SPMI_PMIC_DATA(common, 0xFFFF, 0x39E);
26MTK_SPMI_PMIC_DATA(mt6315, 0x16D0, 0x3A5);
27MTK_SPMI_PMIC_DATA(mt6330, 0x2300, 0x39E);
28
29static const struct of_device_id mtk_spmi_pmic_id_table[] = {
30 { .compatible = "mtk,spmi-pmic", .data = &common_data },
31 { .compatible = "mediatek,mt6315", .data = &mt6315_data },
32 { .compatible = "mediatek,mt6330_fpga", .data = &mt6330_data },
33 { }
34};
35
36static int mtk_spmi_pmic_rw_test(struct regmap *map,
37 const struct mtk_spmi_pmic_data *data)
38{
39 unsigned int rdata = 0, backup;
40 u8 wdata[] = {0xAB, 0xCD};
41 int i, ret;
42
43 ret = regmap_read(map, data->check_reg, &rdata);
44 if (ret)
45 return -EIO;
46 backup = rdata;
47
48 for (i = 0; i < ARRAY_SIZE(wdata); i++) {
49 ret = regmap_write(map, data->check_reg, wdata[i]);
50 ret |= regmap_read(map, data->check_reg, &rdata);
51 if (ret || (rdata != wdata[i])) {
52 pr_notice("%s fail, rdata(0x%x)!=wdata(0x%x)\n",
53 __func__, rdata, wdata[i]);
54 return -EIO;
55 }
56 }
57 ret = regmap_write(map, data->check_reg, backup);
58 return 0;
59}
60
61static int mtk_spmi_pmic_probe(struct spmi_device *sdev)
62{
63 struct regmap_config spmi_regmap_config;
64 struct regmap *regmap;
65 const struct of_device_id *match;
66 const struct mtk_spmi_pmic_data *data;
67 int ret;
68
69 match = of_match_device(mtk_spmi_pmic_id_table, &sdev->dev);
70 if (!match)
71 return -ENODEV;
72 data = (struct mtk_spmi_pmic_data *)match->data;
73 dev_notice(&sdev->dev, "%s usid:%d\n", match->compatible, sdev->usid);
74
75 memset(&spmi_regmap_config, 0, sizeof(struct regmap_config));
76 spmi_regmap_config.reg_bits = 16;
77 spmi_regmap_config.val_bits = 8;
78 spmi_regmap_config.fast_io = true;
79 spmi_regmap_config.max_register = data->max_register;
80 regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
81 if (IS_ERR(regmap))
82 return PTR_ERR(regmap);
83 ret = mtk_spmi_pmic_rw_test(regmap, data);
84 if (ret)
85 return ret;
86
87 return devm_of_platform_populate(&sdev->dev);
88}
89
90MODULE_DEVICE_TABLE(of, mtk_spmi_pmic_id_table);
91
92static struct spmi_driver mtk_spmi_pmic_driver = {
93 .probe = mtk_spmi_pmic_probe,
94 .driver = {
95 .name = "mtk-spmi-pmic",
96 .of_match_table = mtk_spmi_pmic_id_table,
97 },
98};
99module_spmi_driver(mtk_spmi_pmic_driver);
100
101MODULE_DESCRIPTION("Mediatek SPMI PMIC driver");
102MODULE_ALIAS("spmi:spmi-pmic");
103MODULE_LICENSE("GPL v2");
104MODULE_AUTHOR("Argus Lin <argus.lin@mediatek.com>");