blob: dd5bbac47d72571b198c2d3e165bb30482bb96a0 [file] [log] [blame]
/*
* Battery driver for ASR PM802 PMIC
*
* Copyright 2018 ASR Microelectronics (Shanghai) Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/power_supply.h>
#include <linux/mfd/88pm80x.h>
#include <linux/mfd/pm802.h>
#include <linux/mfd/pm813.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/of_device.h>
static int channel_value = 0;
static int adc_channel;
static u32 g_ADC0_conversion_coefficient = 1000; //1.0
static u32 g_ADC1_conversion_coefficient = 1000; //1.0
static int g_board_adc0_channel = 0;
static int g_board_adc1_channel = 1;
#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
#define VABT_DEFAULT_PAIR 20
extern void update_vbat_default_caldata(u8 adc_id, u32 *table,u16 count);
extern void pm803_start_sample_adc(int op,int delay_read_time_ms,u32 read_interval_ms,u16 read_wait_ms);
#endif
static ssize_t pm80x_adc_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "%d", &adc_channel);
channel_value = 0;
#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
pm803_start_sample_adc(1,500,100,20);
#endif
if (adc_channel == 1)
{
channel_value = extern_get_gpadc_volt(g_board_adc1_channel);
}else if (adc_channel == 0){
channel_value = extern_get_gpadc_volt(g_board_adc0_channel);
}
else{
channel_value = 0;
}
#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
pm803_start_sample_adc(2,0,0,0); //restore adc update parameters
#endif
return strnlen(buf, PAGE_SIZE);
}
/*
1806 auxadc linux接口:
extern_get_auxadc_volt(ASR_AUXADC1);
param:
ASR_AUXADC1 = 5
ASR_AUXADC2 = 6
ASR_AUXADC3 = 7
ASR_AUXADC4 = 8
ASR_AUXADC5 = 9
*/
static ssize_t pm80x_adc_shown(struct device *dev,
struct device_attribute *attr, char *buf)
{
int s = 0;
unsigned long level;
u32 coefficient = 1000;
/* for MBTK_PROJECT_L509 :upper resistance 750k + low resistance 270k*/
if(adc_channel == 0)
{
coefficient = g_ADC0_conversion_coefficient;
}
else if(adc_channel == 1)
{
coefficient = g_ADC1_conversion_coefficient;
}
//level = channel_value * 1020 / 270; for L509
level = (channel_value *coefficient)/1000;
s += sprintf(buf, "adc_channel%d=%d\n", adc_channel, level);
return s;
}
static ssize_t asr1806adc_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "%d", &adc_channel);
if (adc_channel == 0)
{
channel_value = extern_get_auxadc_volt(5);
}else if (adc_channel == 1){
channel_value = extern_get_auxadc_volt(8);
}else if (adc_channel == 2){
channel_value = extern_get_auxadc_volt(6);
}else{
channel_value = 0;
}
return strnlen(buf, PAGE_SIZE);
}
static ssize_t asr1806adc_shown(struct device *dev,
struct device_attribute *attr, char *buf)
{
int s = 0;
s += sprintf(buf, "adc_channel%d=%d\n", adc_channel, channel_value);
return s;
}
static DEVICE_ATTR(pm80x_adc, 0644, pm80x_adc_shown, pm80x_adc_store);
static DEVICE_ATTR(aux_adc, 0644, asr1806adc_shown, asr1806adc_store);
static __refdata struct attribute *adc_attrs[] = {
&dev_attr_pm80x_adc.attr,
&dev_attr_aux_adc.attr,
NULL,
};
static __refdata struct attribute_group adc_attr_group = {
.attrs = adc_attrs,
};
static int asr_adc_probe(struct platform_device *pdev)
{
int ret;
struct device_node *np = pdev->dev.of_node;
#if defined(CONFIG_MFD_PM803) && defined(CONFIG_POWER_SUPPLY)
u32 adc0_table[VABT_DEFAULT_PAIR];
u32 adc1_table[VABT_DEFAULT_PAIR];
/*从dts中读取默认校准数据,这只是默认值,还是需要校准的,这个节点用处不大,实际uboot会把默认参数或者校准数据传递到kernel,但如果没有在fal_con_p401.h中开启CONFIG_PM803_GPADC宏
* 则不会从uboot 拷贝默认校准数据,会导致adc采样异常,暂时保留,建议dts数据跟marvell\uboot\drivers\power\pmic\pmic_mrvl_common.c里的数组保持一致
*/
ret = of_property_read_u32_array(np, "vbat_def_pair_table-adc0", adc0_table,VABT_DEFAULT_PAIR);
if(!ret)
{
update_vbat_default_caldata(0,adc0_table,VABT_DEFAULT_PAIR/2);
}
ret = of_property_read_u32_array(np, "vbat_def_pair_table-adc1", adc1_table,VABT_DEFAULT_PAIR);
if(!ret)
{
update_vbat_default_caldata(1,adc1_table,VABT_DEFAULT_PAIR/2);
}
//pm803_adc_init();
#endif
/*mbtk_tanggaoyou add: 有些模块内部有分压电路,则需要设置分压电路的转换系数,注意是针对模块内部的分压电路,不是客户外部的分压电路*/
ret = of_property_read_u32(np, "conversion_coefficient-adc0", &g_ADC0_conversion_coefficient);
if(ret != 0)
{
g_ADC0_conversion_coefficient = 1000;//1.0
}
ret = of_property_read_u32(np, "conversion_coefficient-adc1", &g_ADC1_conversion_coefficient);
if(ret != 0)
{
g_ADC1_conversion_coefficient = 1000;//1.0
}
/*mbtk_tanggaoyou add: 添加adc0_channel和adc1_channel是为了解决L508硬件管脚ADC1对应的是软件的adc1,而ADC2对应的是adc0,需要交换一下*/
ret = of_property_read_u32(np, "adc0_channel", &g_board_adc0_channel); //get ADC0's channel
if(ret != 0)
{
g_board_adc0_channel = 0; //RTN of PM803
}
ret = of_property_read_u32(np, "adc1_channel", &g_board_adc1_channel);//get ADC1's channel
if(ret != 0)
{
g_board_adc1_channel = 1; //RTP of PM803
}
/*mbtk_tanggaoyou add end */
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);
ret = sysfs_create_group(&pdev->dev.kobj, &adc_attr_group);
if (ret) {
printk("--->%s/L%d", __FUNCTION__, __LINE__);
dev_err(&pdev->dev, "adc create sysfs fail!\n");
return ret;
}
return 0;
}
static int asr_adc_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id asr_adc_dt_match[] = {
{ .compatible = "asr,adc", },
{ },
};
MODULE_DEVICE_TABLE(of, asr_adc_dt_match);
static struct platform_driver asr_adc_driver = {
.driver = {
.name = "asr-adc",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(asr_adc_dt_match),
},
.probe = asr_adc_probe,
.remove = asr_adc_remove,
};
static int __init asr_adc_init(void)
{
return platform_driver_register(&asr_adc_driver);
}
module_init(asr_adc_init);
static void __exit asr_adc_exit(void)
{
platform_driver_unregister(&asr_adc_driver);
}
module_exit(asr_adc_exit);
MODULE_DESCRIPTION("ASR PM802 Adc driver");
MODULE_LICENSE("GPL");