blob: dd5bbac47d72571b198c2d3e165bb30482bb96a0 [file] [log] [blame]
b.liub17525e2025-05-14 17:22:29 +08001/*
2 * Battery driver for ASR PM802 PMIC
3 *
4 * Copyright 2018 ASR Microelectronics (Shanghai) Co., Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <linux/slab.h>
15#include <linux/string.h>
16#include <linux/power_supply.h>
17#include <linux/mfd/88pm80x.h>
18#include <linux/mfd/pm802.h>
19#include <linux/mfd/pm813.h>
20#include <linux/delay.h>
21#include <linux/init.h>
22#include <linux/sched.h>
23#include <linux/of_device.h>
24
25
26static int channel_value = 0;
27static int adc_channel;
28static u32 g_ADC0_conversion_coefficient = 1000; //1.0
29static u32 g_ADC1_conversion_coefficient = 1000; //1.0
30static int g_board_adc0_channel = 0;
31static int g_board_adc1_channel = 1;
32
33#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
34#define VABT_DEFAULT_PAIR 20
35extern void update_vbat_default_caldata(u8 adc_id, u32 *table,u16 count);
36extern void pm803_start_sample_adc(int op,int delay_read_time_ms,u32 read_interval_ms,u16 read_wait_ms);
37#endif
38
39
40static ssize_t pm80x_adc_store(struct device *dev,
41 struct device_attribute *attr,
42 const char *buf, size_t count)
43{
44
45 sscanf(buf, "%d", &adc_channel);
46 channel_value = 0;
47
48#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
49 pm803_start_sample_adc(1,500,100,20);
50#endif
51
52 if (adc_channel == 1)
53 {
54 channel_value = extern_get_gpadc_volt(g_board_adc1_channel);
55 }else if (adc_channel == 0){
56 channel_value = extern_get_gpadc_volt(g_board_adc0_channel);
57 }
58 else{
59 channel_value = 0;
60 }
61
62#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
63 pm803_start_sample_adc(2,0,0,0); //restore adc update parameters
64#endif
65
66 return strnlen(buf, PAGE_SIZE);
67}
68
69
70
71/*
72
731806 auxadc linux接口:
74 extern_get_auxadc_volt(ASR_AUXADC1);
75param:
76
77 ASR_AUXADC1 = 5
78 ASR_AUXADC2 = 6
79 ASR_AUXADC3 = 7
80 ASR_AUXADC4 = 8
81 ASR_AUXADC5 = 9
82 */
83
84static ssize_t pm80x_adc_shown(struct device *dev,
85 struct device_attribute *attr, char *buf)
86{
87 int s = 0;
88 unsigned long level;
89 u32 coefficient = 1000;
90
91/* for MBTK_PROJECT_L509 :upper resistance 750k + low resistance 270k*/
92 if(adc_channel == 0)
93 {
94 coefficient = g_ADC0_conversion_coefficient;
95 }
96 else if(adc_channel == 1)
97 {
98 coefficient = g_ADC1_conversion_coefficient;
99 }
100
101 //level = channel_value * 1020 / 270; for L509
102 level = (channel_value *coefficient)/1000;
103
104 s += sprintf(buf, "adc_channel%d=%d\n", adc_channel, level);
105 return s;
106}
107
108
109
110static ssize_t asr1806adc_store(struct device *dev,
111 struct device_attribute *attr,
112 const char *buf, size_t count)
113{
114
115 sscanf(buf, "%d", &adc_channel);
116
117
118 if (adc_channel == 0)
119 {
120 channel_value = extern_get_auxadc_volt(5);
121 }else if (adc_channel == 1){
122 channel_value = extern_get_auxadc_volt(8);
123 }else if (adc_channel == 2){
124 channel_value = extern_get_auxadc_volt(6);
125
126 }else{
127 channel_value = 0;
128 }
129
130 return strnlen(buf, PAGE_SIZE);
131}
132
133static ssize_t asr1806adc_shown(struct device *dev,
134 struct device_attribute *attr, char *buf)
135{
136 int s = 0;
137
138 s += sprintf(buf, "adc_channel%d=%d\n", adc_channel, channel_value);
139 return s;
140}
141
142static DEVICE_ATTR(pm80x_adc, 0644, pm80x_adc_shown, pm80x_adc_store);
143static DEVICE_ATTR(aux_adc, 0644, asr1806adc_shown, asr1806adc_store);
144
145static __refdata struct attribute *adc_attrs[] = {
146 &dev_attr_pm80x_adc.attr,
147 &dev_attr_aux_adc.attr,
148 NULL,
149};
150
151static __refdata struct attribute_group adc_attr_group = {
152 .attrs = adc_attrs,
153};
154
155
156
157
158static int asr_adc_probe(struct platform_device *pdev)
159{
160
161 int ret;
162 struct device_node *np = pdev->dev.of_node;
163
164#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
165 u32 adc0_table[VABT_DEFAULT_PAIR];
166 u32 adc1_table[VABT_DEFAULT_PAIR];
167/*从dts中读取默认校准数据,这只是默认值,还是需要校准的,这个节点用处不大,实际uboot会把默认参数或者校准数据传递到kernel,但如果没有在fal_con_p401.h中开启CONFIG_PM803_GPADC宏
168* 则不会从uboot 拷贝默认校准数据,会导致adc采样异常,暂时保留,建议dts数据跟marvell\uboot\drivers\power\pmic\pmic_mrvl_common.c里的数组保持一致
169*/
170 ret = of_property_read_u32_array(np, "vbat_def_pair_table-adc0", adc0_table,VABT_DEFAULT_PAIR);
171
172 if(!ret)
173 {
174 update_vbat_default_caldata(0,adc0_table,VABT_DEFAULT_PAIR/2);
175 }
176
177 ret = of_property_read_u32_array(np, "vbat_def_pair_table-adc1", adc1_table,VABT_DEFAULT_PAIR);
178
179 if(!ret)
180 {
181 update_vbat_default_caldata(1,adc1_table,VABT_DEFAULT_PAIR/2);
182 }
183
184 //pm803_adc_init();
185#endif
186
187/*mbtk_tanggaoyou add: 有些模块内部有分压电路,则需要设置分压电路的转换系数,注意是针对模块内部的分压电路,不是客户外部的分压电路*/
188 ret = of_property_read_u32(np, "conversion_coefficient-adc0", &g_ADC0_conversion_coefficient);
189 if(ret != 0)
190 {
191 g_ADC0_conversion_coefficient = 1000;//1.0
192 }
193 ret = of_property_read_u32(np, "conversion_coefficient-adc1", &g_ADC1_conversion_coefficient);
194 if(ret != 0)
195 {
196 g_ADC1_conversion_coefficient = 1000;//1.0
197 }
198
199/*mbtk_tanggaoyou add: 添加adc0_channel和adc1_channel是为了解决L508硬件管脚ADC1对应的是软件的adc1,而ADC2对应的是adc0,需要交换一下*/
200 ret = of_property_read_u32(np, "adc0_channel", &g_board_adc0_channel); //get ADC0's channel
201 if(ret != 0)
202 {
203 g_board_adc0_channel = 0; //RTN of PM803
204 }
205 ret = of_property_read_u32(np, "adc1_channel", &g_board_adc1_channel);//get ADC1's channel
206 if(ret != 0)
207 {
208 g_board_adc1_channel = 1; //RTP of PM803
209 }
210/*mbtk_tanggaoyou add end */
211
212 printk("--->%s/L%d,ADC%d,%d,coefficient=%d %d", __FUNCTION__, __LINE__,g_board_adc0_channel,g_board_adc1_channel,g_ADC0_conversion_coefficient,g_ADC1_conversion_coefficient);
213
214 ret = sysfs_create_group(&pdev->dev.kobj, &adc_attr_group);
215 if (ret) {
216 printk("--->%s/L%d", __FUNCTION__, __LINE__);
217 dev_err(&pdev->dev, "adc create sysfs fail!\n");
218 return ret;
219 }
220 return 0;
221}
222
223
224static int asr_adc_remove(struct platform_device *pdev)
225{
226 return 0;
227}
228
229
230static const struct of_device_id asr_adc_dt_match[] = {
231 { .compatible = "asr,adc", },
232 { },
233};
234MODULE_DEVICE_TABLE(of, asr_adc_dt_match);
235
236static struct platform_driver asr_adc_driver = {
237 .driver = {
238 .name = "asr-adc",
239 .owner = THIS_MODULE,
240 .of_match_table = of_match_ptr(asr_adc_dt_match),
241 },
242 .probe = asr_adc_probe,
243 .remove = asr_adc_remove,
244};
245
246static int __init asr_adc_init(void)
247{
248 return platform_driver_register(&asr_adc_driver);
249}
250module_init(asr_adc_init);
251
252static void __exit asr_adc_exit(void)
253{
254 platform_driver_unregister(&asr_adc_driver);
255}
256module_exit(asr_adc_exit);
257
258MODULE_DESCRIPTION("ASR PM802 Adc driver");
259MODULE_LICENSE("GPL");