blob: 741034d1536fd77e2a9c91f22635cbacd78927af [file] [log] [blame]
/*
* s2dos05_powermeter.c
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/regulator/s2dos05.h>
#include <linux/platform_device.h>
#define CURRENT_METER 1
#define POWER_METER 2
#define RAWCURRENT_METER 3
#define SYNC_MODE 1
#define ASYNC_MODE 2
struct adc_info *adc_meter1;
struct device *s2dos05_adc_dev;
struct class *s2dos05_adc_class;
struct adc_info {
struct i2c_client *i2c;
u8 adc_mode;
u8 adc_sync_mode;
u16 *adc_val;
u8 adc_ctrl1;
};
static const unsigned int current_coeffs[8] = {CURRENT_ELVDD, CURRENT_ELVSS, CURRENT_AVDD,
CURRENT_BUCK, CURRENT_L1, CURRENT_L2, CURRENT_L3, CURRENT_L4};
static const unsigned int power_coeffs[8] = {POWER_ELVDD, POWER_ELVSS, POWER_AVDD,
POWER_BUCK, POWER_L1, POWER_L2, POWER_L3, POWER_L4};
static void s2m_adc_read_data(struct device *dev, int channel)
{
int i;
u8 data_l, data_h;
u8 temp;
/* ASYNCRD bit '1' --> 2ms delay --> read in case of ADC Async mode */
if (adc_meter1->adc_sync_mode == ASYNC_MODE) {
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL1, &temp);
if (!(temp & 0x40)) {
if (adc_meter1->adc_mode == CURRENT_METER) {
if (channel < 0) {
for (i = 0; i < 8; i++)
adc_meter1->adc_val[i] = 0;
} else {
adc_meter1->adc_val[channel] = 0;
}
} else if (adc_meter1->adc_mode == POWER_METER) {
if (channel < 0) {
for (i = 0; i < 8; i++)
adc_meter1->adc_val[i] = 0;
} else {
adc_meter1->adc_val[channel] = 0;
}
} else {
dev_err(dev, "%s: invalid adc mode(%d)\n", __func__, adc_meter1->adc_mode);
}
return;
}
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL1, ADC_ASYNCRD_MASK, ADC_ASYNCRD_MASK);
usleep_range(2000, 2100);
}
if (adc_meter1->adc_mode == CURRENT_METER) {
if (channel < 0) {
for (i = 0; i < 8; i++) {
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
i, ADC_PTR_MASK);
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_DATA,
&data_l);
adc_meter1->adc_val[i] = data_l;
}
} else {
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
channel, ADC_PTR_MASK);
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_DATA,
&data_l);
adc_meter1->adc_val[channel] = data_l;
}
} else if (adc_meter1->adc_mode == POWER_METER) {
if (channel < 0) {
for (i = 0; i < 8; i++) {
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
2*i, ADC_PTR_MASK);
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_DATA,
&data_l);
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
2*i+1, ADC_PTR_MASK);
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_DATA,
&data_h);
adc_meter1->adc_val[i] = ((data_h & 0xff) << 8) | (data_l & 0xff);
}
} else {
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
2*channel, ADC_PTR_MASK);
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_DATA,
&data_l);
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
2*channel+1, ADC_PTR_MASK);
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_DATA,
&data_h);
adc_meter1->adc_val[channel] = ((data_h & 0xff) << 8) | (data_l & 0xff);
}
} else {
dev_err(dev, "%s: invalid adc mode(%d)\n", __func__, adc_meter1->adc_mode);
}
}
static unsigned int get_coeff(struct device *dev, u8 adc_reg_num)
{
unsigned int coeff;
if (adc_meter1->adc_mode == CURRENT_METER) {
if (adc_reg_num <= 7)
coeff = current_coeffs[adc_reg_num];
else {
dev_err(dev, "%s: invalid adc regulator number(%d)\n", __func__, adc_reg_num);
coeff = 0;
}
} else if (adc_meter1->adc_mode == POWER_METER) {
if (adc_reg_num <= 7)
coeff = power_coeffs[adc_reg_num];
else {
dev_err(dev, "%s: invalid adc regulator number(%d)\n", __func__, adc_reg_num);
coeff = 0;
}
} else {
dev_err(dev, "%s: invalid adc mode(%d)\n", __func__, adc_meter1->adc_mode);
coeff = 0;
}
return coeff;
}
static ssize_t adc_val_all_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, -1);
if (adc_meter1->adc_mode == POWER_METER) {
return snprintf(buf, PAGE_SIZE, "CH0:%d uW (%d), CH1:%d uW (%d), CH2:%d uW (%d), CH3:%d uW (%d)\nCH4:%d uW (%d), CH5:%d uW (%d), CH6:%d uW (%d), CH7:%d uW (%d)\n",
(adc_meter1->adc_val[0] * get_coeff(dev, 0))/100, adc_meter1->adc_val[0],
(adc_meter1->adc_val[1] * get_coeff(dev, 1))/100, adc_meter1->adc_val[1],
(adc_meter1->adc_val[2] * get_coeff(dev, 2))/100, adc_meter1->adc_val[2],
(adc_meter1->adc_val[3] * get_coeff(dev, 3))/100, adc_meter1->adc_val[3],
(adc_meter1->adc_val[4] * get_coeff(dev, 4))/100, adc_meter1->adc_val[4],
(adc_meter1->adc_val[5] * get_coeff(dev, 5))/100, adc_meter1->adc_val[5],
(adc_meter1->adc_val[6] * get_coeff(dev, 6))/100, adc_meter1->adc_val[6],
(adc_meter1->adc_val[7] * get_coeff(dev, 7))/100, adc_meter1->adc_val[7]);
} else {
return snprintf(buf, PAGE_SIZE, "CH0:%d uA (%d), CH1:%d uA (%d), CH2:%d uA (%d), CH3:%d uA (%d)\nCH4:%d uA (%d), CH5:%d uA (%d), CH6:%d uA (%d), CH7:%d uA (%d)\n",
adc_meter1->adc_val[0] * get_coeff(dev, 0), adc_meter1->adc_val[0],
adc_meter1->adc_val[1] * get_coeff(dev, 1), adc_meter1->adc_val[1],
adc_meter1->adc_val[2] * get_coeff(dev, 2), adc_meter1->adc_val[2],
adc_meter1->adc_val[3] * get_coeff(dev, 3), adc_meter1->adc_val[3],
adc_meter1->adc_val[4] * get_coeff(dev, 4), adc_meter1->adc_val[4],
adc_meter1->adc_val[5] * get_coeff(dev, 5), adc_meter1->adc_val[5],
adc_meter1->adc_val[6] * get_coeff(dev, 6), adc_meter1->adc_val[6],
adc_meter1->adc_val[7] * get_coeff(dev, 7), adc_meter1->adc_val[7]);
}
}
static ssize_t adc_en_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u8 adc_ctrl3;
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2, &adc_ctrl3);
if ((adc_ctrl3 & 0x80) == 0x80)
return snprintf(buf, PAGE_SIZE, "ADC enable (%x)\n", adc_ctrl3);
else
return snprintf(buf, PAGE_SIZE, "ADC disable (%x)\n", adc_ctrl3);
}
static ssize_t adc_en_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
u8 temp, val;
ret = kstrtou8(buf, 16, &temp);
if (ret)
return -EINVAL;
switch (temp) {
case 0:
val = 0x00;
break;
case 1:
val = 0x80;
break;
default:
val = 0x00;
break;
}
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
val, ADC_EN_MASK);
return count;
}
static ssize_t adc_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u8 adc_ctrl3;
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2, &adc_ctrl3);
adc_ctrl3 = adc_ctrl3 & 0x30;
switch (adc_ctrl3) {
case CURRENT_MODE:
return snprintf(buf, PAGE_SIZE, "CURRENT MODE (%d)\n", CURRENT_METER);
case POWER_MODE:
return snprintf(buf, PAGE_SIZE, "POWER MODE (%d)\n", POWER_METER);
default:
return snprintf(buf, PAGE_SIZE, "error (%x)\n", adc_ctrl3);
}
}
static ssize_t adc_mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
u8 temp, val;
ret = kstrtou8(buf, 16, &temp);
if (ret)
return -EINVAL;
switch (temp) {
case CURRENT_METER:
adc_meter1->adc_mode = 1;
val = CURRENT_MODE;
break;
case POWER_METER:
adc_meter1->adc_mode = 2;
val = POWER_MODE;
break;
default:
val = CURRENT_MODE;
break;
}
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2,
(ADC_EN_MASK | val), (ADC_EN_MASK | ADC_PGEN_MASK));
return count;
}
static ssize_t adc_sync_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
switch (adc_meter1->adc_sync_mode) {
case SYNC_MODE:
return snprintf(buf, PAGE_SIZE, "SYNC_MODE (%d)\n", adc_meter1->adc_sync_mode);
case ASYNC_MODE:
return snprintf(buf, PAGE_SIZE, "ASYNC_MODE (%d)\n", adc_meter1->adc_sync_mode);
default:
return snprintf(buf, PAGE_SIZE, "error (%d)\n", adc_meter1->adc_sync_mode);
}
}
static ssize_t adc_sync_mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
u8 temp;
ret = kstrtou8(buf, 16, &temp);
if (ret)
return -EINVAL;
switch (temp) {
case SYNC_MODE:
adc_meter1->adc_sync_mode = 1;
break;
case ASYNC_MODE:
adc_meter1->adc_sync_mode = 2;
break;
default:
adc_meter1->adc_sync_mode = 1;
break;
}
return count;
}
static ssize_t adc_val_0_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 0);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[0] * get_coeff(dev, 0))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[0] * get_coeff(dev, 0));
}
static ssize_t adc_val_1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 1);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[1] * get_coeff(dev, 1))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[1] * get_coeff(dev, 1));
}
static ssize_t adc_val_2_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 2);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[2] * get_coeff(dev, 2))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[2] * get_coeff(dev, 2));
}
static ssize_t adc_val_3_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 3);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[3] * get_coeff(dev, 3))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[3] * get_coeff(dev, 3));
}
static ssize_t adc_val_4_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 4);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[4] * get_coeff(dev, 4))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[4] * get_coeff(dev, 4));
}
static ssize_t adc_val_5_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 5);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[5] * get_coeff(dev, 5))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[5] * get_coeff(dev, 5));
}
static ssize_t adc_val_6_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 6);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[6] * get_coeff(dev, 6))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[6] * get_coeff(dev, 6));
}
static ssize_t adc_val_7_show(struct device *dev, struct device_attribute *attr, char *buf)
{
s2m_adc_read_data(dev, 7);
if (adc_meter1->adc_mode == POWER_METER)
return snprintf(buf, PAGE_SIZE, "%d uW\n", (adc_meter1->adc_val[7] * get_coeff(dev, 7))/100);
else
return snprintf(buf, PAGE_SIZE, "%d uA\n", adc_meter1->adc_val[7] * get_coeff(dev, 7));
}
static void adc_ctrl1_update(struct device *dev)
{
/* ADC temporarily off */
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2, 0x00, ADC_EN_MASK);
/* update ADC_CTRL1 register */
s2dos05_write_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL1, adc_meter1->adc_ctrl1);
/* ADC Continuous ON */
s2dos05_update_reg(adc_meter1->i2c, S2DOS05_REG_PWRMT_CTRL2, ADC_EN_MASK, ADC_EN_MASK);
}
static ssize_t adc_ctrl1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "0x%2x\n", adc_meter1->adc_ctrl1);
}
static ssize_t adc_ctrl1_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
u8 temp;
ret = kstrtou8(buf, 16, &temp);
if (ret)
return -EINVAL;
temp &= 0x0f;
adc_meter1->adc_ctrl1 &= 0xf0;
adc_meter1->adc_ctrl1 |= temp;
adc_ctrl1_update(dev);
return count;
}
#ifdef CONFIG_SEC_PM
static ssize_t adc_validity_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u8 adc_validity;
s2dos05_read_reg(adc_meter1->i2c, S2DOS05_REG_OCL, &adc_validity);
return snprintf(buf, PAGE_SIZE, "%d\n", (adc_validity >> 7));
}
#endif /* CONFIG_SEC_PM */
static DEVICE_ATTR(adc_val_all, 0444, adc_val_all_show, NULL);
static DEVICE_ATTR(adc_en, 0644, adc_en_show, adc_en_store);
static DEVICE_ATTR(adc_mode, 0644, adc_mode_show, adc_mode_store);
static DEVICE_ATTR(adc_sync_mode, 0644, adc_sync_mode_show, adc_sync_mode_store);
static DEVICE_ATTR(adc_val_0, 0444, adc_val_0_show, NULL);
static DEVICE_ATTR(adc_val_1, 0444, adc_val_1_show, NULL);
static DEVICE_ATTR(adc_val_2, 0444, adc_val_2_show, NULL);
static DEVICE_ATTR(adc_val_3, 0444, adc_val_3_show, NULL);
static DEVICE_ATTR(adc_val_4, 0444, adc_val_4_show, NULL);
static DEVICE_ATTR(adc_val_5, 0444, adc_val_5_show, NULL);
static DEVICE_ATTR(adc_val_6, 0444, adc_val_6_show, NULL);
static DEVICE_ATTR(adc_val_7, 0444, adc_val_7_show, NULL);
static DEVICE_ATTR(adc_ctrl1, 0644, adc_ctrl1_show, adc_ctrl1_store);
#ifdef CONFIG_SEC_PM
static DEVICE_ATTR(adc_validity, 0444, adc_validity_show, NULL);
#endif /* CONFIG_SEC_PM */
void s2dos05_powermeter_init(struct s2dos05_dev *s2dos05,
struct device *sec_disp_pmic_dev)
{
int ret;
adc_meter1 = kzalloc(sizeof(struct adc_info), GFP_KERNEL);
if (!adc_meter1) {
pr_err("%s: adc_meter1 alloc fail.\n", __func__);
return;
}
adc_meter1->adc_val = kzalloc(sizeof(u16)*S2DOS05_MAX_ADC_CHANNEL, GFP_KERNEL);
pr_info("%s: s2dos05 power meter init start\n", __func__);
/* adc_reg[] : ELVDD, ELVSS, AVDD, BUCK, LDO1. LDO2, LDO3, LDO4 */
adc_meter1->adc_mode = s2dos05->adc_mode;
adc_meter1->adc_sync_mode = s2dos05->adc_sync_mode;
/* POWER_METER mode needs bigger SMP_NUM to get stable value */
switch (adc_meter1->adc_mode) {
case CURRENT_METER:
adc_meter1->adc_ctrl1 = 0x0C;
break;
case POWER_METER:
adc_meter1->adc_ctrl1 = 0x0C;
break;
default:
adc_meter1->adc_ctrl1 = 0x0C;
break;
}
/* SMP_NUM = 1100(16384) ~16s in case of aync mode */
if (adc_meter1->adc_sync_mode == ASYNC_MODE)
adc_meter1->adc_ctrl1 = 0x0C;
s2dos05_write_reg(s2dos05->i2c, S2DOS05_REG_PWRMT_CTRL1, adc_meter1->adc_ctrl1);
/* IRQM unmask */
/* s2dos05_update_reg(s2dos05->i2c, S2DOS05_REG_IRQ_MASK, 0x00); */
/* ADC EN */
switch (adc_meter1->adc_mode) {
case CURRENT_METER:
s2dos05_update_reg(s2dos05->i2c, S2DOS05_REG_PWRMT_CTRL2,
(ADC_EN_MASK | CURRENT_MODE), (ADC_EN_MASK | ADC_PGEN_MASK));
pr_info("%s: current mode enable (0x%2x)\n",
__func__, (ADC_EN_MASK | CURRENT_MODE));
break;
case POWER_METER:
s2dos05_update_reg(s2dos05->i2c, S2DOS05_REG_PWRMT_CTRL2,
(ADC_EN_MASK | POWER_MODE), (ADC_EN_MASK | ADC_PGEN_MASK));
pr_info("%s: power mode enable (0x%2x)\n",
__func__, (ADC_EN_MASK | POWER_MODE));
break;
default:
s2dos05_update_reg(s2dos05->i2c, S2DOS05_REG_PWRMT_CTRL2,
(0x00 | CURRENT_MODE), (ADC_EN_MASK | ADC_PGEN_MASK));
pr_info("%s: current/power meter disable (0x%2x)\n",
__func__, (ADC_EN_MASK | CURRENT_MODE));
}
adc_meter1->i2c = s2dos05->i2c;
s2dos05_adc_class = class_create(THIS_MODULE, "adc_meter1");
s2dos05_adc_dev = device_create(s2dos05_adc_class, NULL, 0, NULL, "s2dos05_adc");
/* create sysfs entries */
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_en);
if (ret)
goto err_free;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_mode);
if (ret)
goto remove_adc_en;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_sync_mode);
if (ret)
goto remove_adc_mode;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_all);
if (ret)
goto remove_adc_sync_mode;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_0);
if (ret)
goto remove_adc_val_all;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_1);
if (ret)
goto remove_adc_val_0;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_2);
if (ret)
goto remove_adc_val_1;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_3);
if (ret)
goto remove_adc_val_2;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_4);
if (ret)
goto remove_adc_val_3;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_5);
if (ret)
goto remove_adc_val_4;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_6);
if (ret)
goto remove_adc_val_5;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_val_7);
if (ret)
goto remove_adc_val_6;
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_ctrl1);
if (ret)
goto remove_adc_val_7;
#ifdef CONFIG_SEC_PM
ret = device_create_file(s2dos05_adc_dev, &dev_attr_adc_validity);
if (ret)
goto remove_adc_ctrl1;
if (!IS_ERR_OR_NULL(sec_disp_pmic_dev)) {
ret = sysfs_create_link(&sec_disp_pmic_dev->kobj,
&s2dos05_adc_dev->kobj, "power_meter");
if (ret) {
pr_err("%s: fail to create link for power_meter\n",
__func__);
goto remove_adc_validity;
}
}
#endif /* CONFIG_SEC_PM */
pr_info("%s: s2dos05 power meter init end\n", __func__);
return;
#ifdef CONFIG_SEC_PM
remove_adc_validity:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_validity);
remove_adc_ctrl1:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_ctrl1);
#endif /* CONFIG_SEC_PM */
remove_adc_val_7:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_7);
remove_adc_val_6:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_6);
remove_adc_val_5:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_5);
remove_adc_val_4:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_4);
remove_adc_val_3:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_3);
remove_adc_val_2:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_2);
remove_adc_val_1:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_1);
remove_adc_val_0:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_0);
remove_adc_val_all:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_all);
remove_adc_sync_mode:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_sync_mode);
remove_adc_mode:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_mode);
remove_adc_en:
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_en);
err_free:
kfree(adc_meter1->adc_val);
dev_info(s2dos05->dev, "%s : fail to create sysfs\n", __func__);
}
void s2dos05_powermeter_deinit(struct s2dos05_dev *s2dos05)
{
/* remove sysfs entries */
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_en);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_all);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_mode);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_sync_mode);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_0);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_1);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_2);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_3);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_4);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_5);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_6);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_val_7);
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_ctrl1);
#ifdef CONFIG_SEC_PM
device_remove_file(s2dos05_adc_dev, &dev_attr_adc_validity);
#endif /* CONFIG_SEC_PM */
/* ADC turned off */
s2dos05_write_reg(s2dos05->i2c, S2DOS05_REG_PWRMT_CTRL2, 0);
kfree(adc_meter1->adc_val);
pr_info("%s: s2dos05 power meter deinit\n", __func__);
}