hwmon: Add pm8xxx ADC driver

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
Stephen Boyd 2013-01-11 16:44:15 -08:00
parent 37d05847f1
commit 3934abf514
5 changed files with 2659 additions and 0 deletions

View file

@ -969,6 +969,15 @@ config SENSORS_MSM_ADC
internally uses an array of LTC2499 and EPM ADCs in a differential
configuration to provide a flat set of channels that can be addressed.
config SENSORS_PM8XXX_ADC
tristate "Support for Qualcomm PM8XXX ADC"
depends on MFD_PM8XXX
help
This is the ADC arbiter driver for Qualcomm PM8XXX Chip.
The driver supports reading the HKADC, XOADC and support to set and receive
temperature threshold notifications using the Battery temperature module.
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
depends on !PPC

View file

@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_WPCE775X) += wpce775x.o
obj-$(CONFIG_SENSORS_MSM_ADC) += msm_adc.o m_adcproc.o
obj-$(CONFIG_SENSORS_PM8XXX_ADC) += pm8xxx-adc.o pm8xxx-adc-scale.o
obj-$(CONFIG_PMBUS) += pmbus/

View file

@ -0,0 +1,738 @@
/*
* Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#define KELVINMIL_DEGMIL 273160
/* Units for temperature below (on x axis) is in 0.1DegC as
required by the battery driver. Note the resolution used
here to compute the table was done for DegC to milli-volts.
In consideration to limit the size of the table for the given
temperature range below, the result is linearly interpolated
and provided to the battery driver in the units desired for
their framework which is 0.1DegC. True resolution of 0.1DegC
will result in the below table size to increase by 10 times */
static const struct pm8xxx_adc_map_pt adcmap_btm_threshold[] = {
{-300, 1642},
{-200, 1544},
{-100, 1414},
{0, 1260},
{10, 1244},
{20, 1228},
{30, 1212},
{40, 1195},
{50, 1179},
{60, 1162},
{70, 1146},
{80, 1129},
{90, 1113},
{100, 1097},
{110, 1080},
{120, 1064},
{130, 1048},
{140, 1032},
{150, 1016},
{160, 1000},
{170, 985},
{180, 969},
{190, 954},
{200, 939},
{210, 924},
{220, 909},
{230, 894},
{240, 880},
{250, 866},
{260, 852},
{270, 838},
{280, 824},
{290, 811},
{300, 798},
{310, 785},
{320, 773},
{330, 760},
{340, 748},
{350, 736},
{360, 725},
{370, 713},
{380, 702},
{390, 691},
{400, 681},
{410, 670},
{420, 660},
{430, 650},
{440, 640},
{450, 631},
{460, 622},
{470, 613},
{480, 604},
{490, 595},
{500, 587},
{510, 579},
{520, 571},
{530, 563},
{540, 556},
{550, 548},
{560, 541},
{570, 534},
{580, 527},
{590, 521},
{600, 514},
{610, 508},
{620, 502},
{630, 496},
{640, 490},
{650, 485},
{660, 281},
{670, 274},
{680, 267},
{690, 260},
{700, 254},
{710, 247},
{720, 241},
{730, 235},
{740, 229},
{750, 224},
{760, 218},
{770, 213},
{780, 208},
{790, 203}
};
static const struct pm8xxx_adc_map_pt adcmap_pa_therm[] = {
{1677, -30},
{1671, -29},
{1663, -28},
{1656, -27},
{1648, -26},
{1640, -25},
{1632, -24},
{1623, -23},
{1615, -22},
{1605, -21},
{1596, -20},
{1586, -19},
{1576, -18},
{1565, -17},
{1554, -16},
{1543, -15},
{1531, -14},
{1519, -13},
{1507, -12},
{1494, -11},
{1482, -10},
{1468, -9},
{1455, -8},
{1441, -7},
{1427, -6},
{1412, -5},
{1398, -4},
{1383, -3},
{1367, -2},
{1352, -1},
{1336, 0},
{1320, 1},
{1304, 2},
{1287, 3},
{1271, 4},
{1254, 5},
{1237, 6},
{1219, 7},
{1202, 8},
{1185, 9},
{1167, 10},
{1149, 11},
{1131, 12},
{1114, 13},
{1096, 14},
{1078, 15},
{1060, 16},
{1042, 17},
{1024, 18},
{1006, 19},
{988, 20},
{970, 21},
{952, 22},
{934, 23},
{917, 24},
{899, 25},
{882, 26},
{865, 27},
{848, 28},
{831, 29},
{814, 30},
{797, 31},
{781, 32},
{764, 33},
{748, 34},
{732, 35},
{717, 36},
{701, 37},
{686, 38},
{671, 39},
{656, 40},
{642, 41},
{627, 42},
{613, 43},
{599, 44},
{586, 45},
{572, 46},
{559, 47},
{546, 48},
{534, 49},
{522, 50},
{509, 51},
{498, 52},
{486, 53},
{475, 54},
{463, 55},
{452, 56},
{442, 57},
{431, 58},
{421, 59},
{411, 60},
{401, 61},
{392, 62},
{383, 63},
{374, 64},
{365, 65},
{356, 66},
{348, 67},
{339, 68},
{331, 69},
{323, 70},
{316, 71},
{308, 72},
{301, 73},
{294, 74},
{287, 75},
{280, 76},
{273, 77},
{267, 78},
{261, 79},
{255, 80},
{249, 81},
{243, 82},
{237, 83},
{232, 84},
{226, 85},
{221, 86},
{216, 87},
{211, 88},
{206, 89},
{201, 90}
};
static const struct pm8xxx_adc_map_pt adcmap_ntcg_104ef_104fb[] = {
{696483, -40960},
{649148, -39936},
{605368, -38912},
{564809, -37888},
{527215, -36864},
{492322, -35840},
{460007, -34816},
{429982, -33792},
{402099, -32768},
{376192, -31744},
{352075, -30720},
{329714, -29696},
{308876, -28672},
{289480, -27648},
{271417, -26624},
{254574, -25600},
{238903, -24576},
{224276, -23552},
{210631, -22528},
{197896, -21504},
{186007, -20480},
{174899, -19456},
{164521, -18432},
{154818, -17408},
{145744, -16384},
{137265, -15360},
{129307, -14336},
{121866, -13312},
{114896, -12288},
{108365, -11264},
{102252, -10240},
{96499, -9216},
{91111, -8192},
{86055, -7168},
{81308, -6144},
{76857, -5120},
{72660, -4096},
{68722, -3072},
{65020, -2048},
{61538, -1024},
{58261, 0},
{55177, 1024},
{52274, 2048},
{49538, 3072},
{46962, 4096},
{44531, 5120},
{42243, 6144},
{40083, 7168},
{38045, 8192},
{36122, 9216},
{34308, 10240},
{32592, 11264},
{30972, 12288},
{29442, 13312},
{27995, 14336},
{26624, 15360},
{25333, 16384},
{24109, 17408},
{22951, 18432},
{21854, 19456},
{20807, 20480},
{19831, 21504},
{18899, 22528},
{18016, 23552},
{17178, 24576},
{16384, 25600},
{15631, 26624},
{14916, 27648},
{14237, 28672},
{13593, 29696},
{12976, 30720},
{12400, 31744},
{11848, 32768},
{11324, 33792},
{10825, 34816},
{10354, 35840},
{9900, 36864},
{9471, 37888},
{9062, 38912},
{8674, 39936},
{8306, 40960},
{7951, 41984},
{7616, 43008},
{7296, 44032},
{6991, 45056},
{6701, 46080},
{6424, 47104},
{6160, 48128},
{5908, 49152},
{5667, 50176},
{5439, 51200},
{5219, 52224},
{5010, 53248},
{4810, 54272},
{4619, 55296},
{4440, 56320},
{4263, 57344},
{4097, 58368},
{3938, 59392},
{3785, 60416},
{3637, 61440},
{3501, 62464},
{3368, 63488},
{3240, 64512},
{3118, 65536},
{2998, 66560},
{2889, 67584},
{2782, 68608},
{2680, 69632},
{2581, 70656},
{2490, 71680},
{2397, 72704},
{2310, 73728},
{2227, 74752},
{2147, 75776},
{2064, 76800},
{1998, 77824},
{1927, 78848},
{1860, 79872},
{1795, 80896},
{1736, 81920},
{1673, 82944},
{1615, 83968},
{1560, 84992},
{1507, 86016},
{1456, 87040},
{1407, 88064},
{1360, 89088},
{1314, 90112},
{1271, 91136},
{1228, 92160},
{1189, 93184},
{1150, 94208},
{1112, 95232},
{1076, 96256},
{1042, 97280},
{1008, 98304},
{976, 99328},
{945, 100352},
{915, 101376},
{886, 102400},
{859, 103424},
{832, 104448},
{807, 105472},
{782, 106496},
{756, 107520},
{735, 108544},
{712, 109568},
{691, 110592},
{670, 111616},
{650, 112640},
{631, 113664},
{612, 114688},
{594, 115712},
{577, 116736},
{560, 117760},
{544, 118784},
{528, 119808},
{513, 120832},
{498, 121856},
{483, 122880},
{470, 123904},
{457, 124928},
{444, 125952},
{431, 126976},
{419, 128000}
};
static int32_t pm8xxx_adc_map_linear(const struct pm8xxx_adc_map_pt *pts,
uint32_t tablesize, int32_t input, int64_t *output)
{
bool descending = 1;
uint32_t i = 0;
if ((pts == NULL) || (output == NULL))
return -EINVAL;
/* Check if table is descending or ascending */
if (tablesize > 1) {
if (pts[0].x < pts[1].x)
descending = 0;
}
while (i < tablesize) {
if ((descending == 1) && (pts[i].x < input)) {
/* table entry is less than measured
value and table is descending, stop */
break;
} else if ((descending == 0) &&
(pts[i].x > input)) {
/* table entry is greater than measured
value and table is ascending, stop */
break;
} else {
i++;
}
}
if (i == 0)
*output = pts[0].y;
else if (i == tablesize)
*output = pts[tablesize-1].y;
else {
/* result is between search_index and search_index-1 */
/* interpolate linearly */
*output = (((int32_t) ((pts[i].y - pts[i-1].y)*
(input - pts[i-1].x))/
(pts[i].x - pts[i-1].x))+
pts[i-1].y);
}
return 0;
}
static int32_t pm8xxx_adc_map_batt_therm(const struct pm8xxx_adc_map_pt *pts,
uint32_t tablesize, int32_t input, int64_t *output)
{
bool descending = 1;
uint32_t i = 0;
if ((pts == NULL) || (output == NULL))
return -EINVAL;
/* Check if table is descending or ascending */
if (tablesize > 1) {
if (pts[0].y < pts[1].y)
descending = 0;
}
while (i < tablesize) {
if ((descending == 1) && (pts[i].y < input)) {
/* table entry is less than measured
value and table is descending, stop */
break;
} else if ((descending == 0) && (pts[i].y > input)) {
/* table entry is greater than measured
value and table is ascending, stop */
break;
} else {
i++;
}
}
if (i == 0) {
*output = pts[0].x;
} else if (i == tablesize) {
*output = pts[tablesize-1].x;
} else {
/* result is between search_index and search_index-1 */
/* interpolate linearly */
*output = (((int32_t) ((pts[i].x - pts[i-1].x)*
(input - pts[i-1].y))/
(pts[i].y - pts[i-1].y))+
pts[i-1].x);
}
return 0;
}
int32_t pm8xxx_adc_scale_default(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties,
struct pm8xxx_adc_chan_result *adc_chan_result)
{
bool negative_rawfromoffset = 0, negative_offset = 0;
int64_t scale_voltage = 0;
if (!chan_properties || !chan_properties->offset_gain_numerator ||
!chan_properties->offset_gain_denominator || !adc_properties
|| !adc_chan_result)
return -EINVAL;
scale_voltage = (adc_code -
chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd)
* chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
if (scale_voltage < 0) {
negative_offset = 1;
scale_voltage = -scale_voltage;
}
do_div(scale_voltage,
chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy);
if (negative_offset)
scale_voltage = -scale_voltage;
scale_voltage += chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
if (scale_voltage < 0) {
if (adc_properties->bipolar) {
scale_voltage = -scale_voltage;
negative_rawfromoffset = 1;
} else {
scale_voltage = 0;
}
}
adc_chan_result->measurement = scale_voltage *
chan_properties->offset_gain_denominator;
/* do_div only perform positive integer division! */
do_div(adc_chan_result->measurement,
chan_properties->offset_gain_numerator);
if (negative_rawfromoffset)
adc_chan_result->measurement = -adc_chan_result->measurement;
/* Note: adc_chan_result->measurement is in the unit of
* adc_properties.adc_reference. For generic channel processing,
* channel measurement is a scale/ratio relative to the adc
* reference input */
adc_chan_result->physical = adc_chan_result->measurement;
return 0;
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_default);
static int64_t pm8xxx_adc_scale_ratiometric_calib(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties)
{
int64_t adc_voltage = 0;
bool negative_offset = 0;
if (!chan_properties || !chan_properties->offset_gain_numerator ||
!chan_properties->offset_gain_denominator || !adc_properties)
return -EINVAL;
adc_voltage = (adc_code -
chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd)
* adc_properties->adc_vdd_reference;
if (adc_voltage < 0) {
negative_offset = 1;
adc_voltage = -adc_voltage;
}
do_div(adc_voltage,
chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy);
if (negative_offset)
adc_voltage = -adc_voltage;
return adc_voltage;
}
int32_t pm8xxx_adc_scale_batt_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties,
struct pm8xxx_adc_chan_result *adc_chan_result)
{
int64_t bat_voltage = 0;
bat_voltage = pm8xxx_adc_scale_ratiometric_calib(adc_code,
adc_properties, chan_properties);
return pm8xxx_adc_map_batt_therm(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
bat_voltage,
&adc_chan_result->physical);
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_batt_therm);
int32_t pm8xxx_adc_scale_pa_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties,
struct pm8xxx_adc_chan_result *adc_chan_result)
{
int64_t pa_voltage = 0;
pa_voltage = pm8xxx_adc_scale_ratiometric_calib(adc_code,
adc_properties, chan_properties);
return pm8xxx_adc_map_linear(
adcmap_pa_therm,
ARRAY_SIZE(adcmap_pa_therm),
pa_voltage,
&adc_chan_result->physical);
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_pa_therm);
int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties,
struct pm8xxx_adc_chan_result *adc_chan_result)
{
int64_t batt_id_voltage = 0;
batt_id_voltage = pm8xxx_adc_scale_ratiometric_calib(adc_code,
adc_properties, chan_properties);
adc_chan_result->physical = batt_id_voltage;
adc_chan_result->physical = adc_chan_result->measurement;
return 0;
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_batt_id);
int32_t pm8xxx_adc_scale_pmic_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties,
struct pm8xxx_adc_chan_result *adc_chan_result)
{
int64_t pmic_voltage = 0;
bool negative_offset = 0;
if (!chan_properties || !chan_properties->offset_gain_numerator ||
!chan_properties->offset_gain_denominator || !adc_properties
|| !adc_chan_result)
return -EINVAL;
pmic_voltage = (adc_code -
chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd)
* chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
if (pmic_voltage < 0) {
negative_offset = 1;
pmic_voltage = -pmic_voltage;
}
do_div(pmic_voltage,
chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy);
if (negative_offset)
pmic_voltage = -pmic_voltage;
pmic_voltage += chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
if (pmic_voltage > 0) {
/* 2mV/K */
adc_chan_result->measurement = pmic_voltage*
chan_properties->offset_gain_denominator;
do_div(adc_chan_result->measurement,
chan_properties->offset_gain_numerator * 2);
} else {
adc_chan_result->measurement = 0;
}
/* Change to .001 deg C */
adc_chan_result->measurement -= KELVINMIL_DEGMIL;
adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
return 0;
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_pmic_therm);
/* Scales the ADC code to 0.001 degrees C using the map
* table for the XO thermistor.
*/
int32_t pm8xxx_adc_tdkntcg_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties,
struct pm8xxx_adc_chan_result *adc_chan_result)
{
int64_t xo_thm = 0;
if (!chan_properties || !chan_properties->offset_gain_numerator ||
!chan_properties->offset_gain_denominator || !adc_properties
|| !adc_chan_result)
return -EINVAL;
xo_thm = pm8xxx_adc_scale_ratiometric_calib(adc_code,
adc_properties, chan_properties);
xo_thm <<= 4;
pm8xxx_adc_map_linear(adcmap_ntcg_104ef_104fb,
ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
xo_thm, &adc_chan_result->physical);
return 0;
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_tdkntcg_therm);
int32_t pm8xxx_adc_batt_scaler(struct pm8xxx_adc_arb_btm_param *btm_param,
const struct pm8xxx_adc_properties *adc_properties,
const struct pm8xxx_adc_chan_properties *chan_properties)
{
int rc;
rc = pm8xxx_adc_map_linear(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
(btm_param->low_thr_temp),
&btm_param->low_thr_voltage);
if (rc)
return rc;
btm_param->low_thr_voltage *=
chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy;
do_div(btm_param->low_thr_voltage, adc_properties->adc_vdd_reference);
btm_param->low_thr_voltage +=
chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd;
rc = pm8xxx_adc_map_linear(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
(btm_param->high_thr_temp),
&btm_param->high_thr_voltage);
if (rc)
return rc;
btm_param->high_thr_voltage *=
chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy;
do_div(btm_param->high_thr_voltage, adc_properties->adc_vdd_reference);
btm_param->high_thr_voltage +=
chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd;
return rc;
}
EXPORT_SYMBOL_GPL(pm8xxx_adc_batt_scaler);

1307
drivers/hwmon/pm8xxx-adc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,604 @@
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Qualcomm PMIC 8921/8018 ADC driver header file
*
*/
#ifndef __PM8XXX_ADC_H
#define __PM8XXX_ADC_H
#include <linux/kernel.h>
#include <linux/list.h>
/**
* enum pm8xxx_adc_channels - PM8XXX AMUX arbiter channels
* %CHANNEL_VCOIN: Backup voltage for certain register set
* %CHANNEL_VBAT: Battery voltage
* %CHANNEL_DCIN: Charger input voltage without internal OVP
* %CHANNEL_ICHG: Charge-current monitor
* %CHANNEL_VPH_PWR: Main system power
* %CHANNEL_IBAT: Battery charge current
* %CHANNEL_MPP_1: 16:1 pre-mux unity scale MPP input
* %CHANNEL_MPP_2: 16:1 pre-mux 1/3 scale MPP input
* %CHANNEL_BATT_THERM: Battery temperature
* %CHANNEL_BATT_ID: Battery detection
* %CHANNEL_USBIN: Charger input voltage with internal OVP
* %CHANNEL_DIE_TEMP: Pmic_die temperature
* %CHANNEL_625MV: 625mv reference channel
* %CHANNEL_125V: 1.25v reference channel
* %CHANNEL_CHG_TEMP: Charger temperature
* %CHANNEL_MUXOFF: Channel to reduce input load on the mux
* %CHANNEL_NONE: Do not use this channel
*/
enum pm8xxx_adc_channels {
CHANNEL_VCOIN = 0,
CHANNEL_VBAT,
CHANNEL_DCIN,
CHANNEL_ICHG,
CHANNEL_VPH_PWR,
CHANNEL_IBAT,
CHANNEL_MPP_1,
CHANNEL_MPP_2,
CHANNEL_BATT_THERM,
/* PM8018 ADC Arbiter uses a single channel on AMUX8
* to read either Batt_id or Batt_therm.
*/
CHANNEL_BATT_ID_THERM = CHANNEL_BATT_THERM,
CHANNEL_BATT_ID,
CHANNEL_USBIN,
CHANNEL_DIE_TEMP,
CHANNEL_625MV,
CHANNEL_125V,
CHANNEL_CHG_TEMP,
CHANNEL_MUXOFF,
CHANNEL_NONE,
ADC_MPP_1_ATEST_8 = 20,
ADC_MPP_1_USB_SNS_DIV20,
ADC_MPP_1_DCIN_SNS_DIV20,
ADC_MPP_1_AMUX3,
ADC_MPP_1_AMUX4,
ADC_MPP_1_AMUX5,
ADC_MPP_1_AMUX6,
ADC_MPP_1_AMUX7,
ADC_MPP_1_AMUX8,
ADC_MPP_1_ATEST_1,
ADC_MPP_1_ATEST_2,
ADC_MPP_1_ATEST_3,
ADC_MPP_1_ATEST_4,
ADC_MPP_1_ATEST_5,
ADC_MPP_1_ATEST_6,
ADC_MPP_1_ATEST_7,
ADC_MPP_2_ATEST_8 = 40,
ADC_MPP_2_USB_SNS_DIV20,
ADC_MPP_2_DCIN_SNS_DIV20,
ADC_MPP_2_AMUX3,
ADC_MPP_2_AMUX4,
ADC_MPP_2_AMUX5,
ADC_MPP_2_AMUX6,
ADC_MPP_2_AMUX7,
ADC_MPP_2_AMUX8,
ADC_MPP_2_ATEST_1,
ADC_MPP_2_ATEST_2,
ADC_MPP_2_ATEST_3,
ADC_MPP_2_ATEST_4,
ADC_MPP_2_ATEST_5,
ADC_MPP_2_ATEST_6,
ADC_MPP_2_ATEST_7,
ADC_CHANNEL_MAX_NUM,
};
#define PM8XXX_ADC_PMIC_0 0x0
#define PM8XXX_CHANNEL_ADC_625_UV 625000
#define PM8XXX_CHANNEL_MPP_SCALE1_IDX 20
#define PM8XXX_CHANNEL_MPP_SCALE3_IDX 40
#define PM8XXX_AMUX_MPP_3 0x3
#define PM8XXX_AMUX_MPP_4 0x4
#define PM8XXX_AMUX_MPP_5 0x5
#define PM8XXX_AMUX_MPP_6 0x6
#define PM8XXX_AMUX_MPP_7 0x7
#define PM8XXX_AMUX_MPP_8 0x8
#define PM8XXX_ADC_DEV_NAME "pm8xxx-adc"
/**
* enum pm8xxx_adc_decimation_type - Sampling rate supported
* %ADC_DECIMATION_TYPE1: 512
* %ADC_DECIMATION_TYPE2: 1K
* %ADC_DECIMATION_TYPE3: 2K
* %ADC_DECIMATION_TYPE4: 4k
* %ADC_DECIMATION_NONE: Do not use this Sampling type
*
* The Sampling rate is specific to each channel of the PM8XXX ADC arbiter.
*/
enum pm8xxx_adc_decimation_type {
ADC_DECIMATION_TYPE1 = 0,
ADC_DECIMATION_TYPE2,
ADC_DECIMATION_TYPE3,
ADC_DECIMATION_TYPE4,
ADC_DECIMATION_NONE,
};
/**
* enum pm8xxx_adc_calib_type - PM8XXX ADC Calibration type
* %ADC_CALIB_ABSOLUTE: Use 625mV and 1.25V reference channels
* %ADC_CALIB_RATIOMETRIC: Use reference Voltage/GND
* %ADC_CALIB_CONFIG_NONE: Do not use this calibration type
*
* Use the input reference voltage depending on the calibration type
* to calcluate the offset and gain parameters. The calibration is
* specific to each channel of the PM8XXX ADC.
*/
enum pm8xxx_adc_calib_type {
ADC_CALIB_ABSOLUTE = 0,
ADC_CALIB_RATIOMETRIC,
ADC_CALIB_NONE,
};
/**
* enum pm8xxx_adc_channel_scaling_param - pre-scaling AMUX ratio
* %CHAN_PATH_SCALING1: ratio of {1, 1}
* %CHAN_PATH_SCALING2: ratio of {1, 3}
* %CHAN_PATH_SCALING3: ratio of {1, 4}
* %CHAN_PATH_SCALING4: ratio of {1, 6}
* %CHAN_PATH_NONE: Do not use this pre-scaling ratio type
*
* The pre-scaling is applied for signals to be within the voltage range
* of the ADC.
*/
enum pm8xxx_adc_channel_scaling_param {
CHAN_PATH_SCALING1 = 0,
CHAN_PATH_SCALING2,
CHAN_PATH_SCALING3,
CHAN_PATH_SCALING4,
CHAN_PATH_SCALING_NONE,
};
/**
* enum pm8xxx_adc_amux_input_rsv - HK/XOADC reference voltage
* %AMUX_RSV0: XO_IN/XOADC_GND
* %AMUX_RSV1: PMIC_IN/XOADC_GND
* %AMUX_RSV2: PMIC_IN/BMS_CSP
* %AMUX_RSV3: not used
* %AMUX_RSV4: XOADC_GND/XOADC_GND
* %AMUX_RSV5: XOADC_VREF/XOADC_GND
* %AMUX_NONE: Do not use this input reference voltage selection
*/
enum pm8xxx_adc_amux_input_rsv {
AMUX_RSV0 = 0,
AMUX_RSV1,
AMUX_RSV2,
AMUX_RSV3,
AMUX_RSV4,
AMUX_RSV5,
AMUX_NONE,
};
/**
* enum pm8xxx_adc_premux_mpp_scale_type - 16:1 pre-mux scale ratio
* %PREMUX_MPP_SCALE_0: No scaling to the input signal
* %PREMUX_MPP_SCALE_1: Unity scaling selected by the user for MPP input
* %PREMUX_MPP_SCALE_1_DIV3: 1/3 pre-scale to the input MPP signal
* %PREMUX_MPP_NONE: Do not use this pre-scale mpp type
*/
enum pm8xxx_adc_premux_mpp_scale_type {
PREMUX_MPP_SCALE_0 = 0,
PREMUX_MPP_SCALE_1,
PREMUX_MPP_SCALE_1_DIV3,
PREMUX_MPP_NONE,
};
/**
* enum pm8xxx_adc_scale_fn_type - Scaling function for pm8921 pre calibrated
* digital data relative to ADC reference
* %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage
* %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters
* %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade
* %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor
* %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade
* %ADC_SCALE_NONE: Do not use this scaling type
*/
enum pm8xxx_adc_scale_fn_type {
ADC_SCALE_DEFAULT = 0,
ADC_SCALE_BATT_THERM,
ADC_SCALE_PA_THERM,
ADC_SCALE_PMIC_THERM,
ADC_SCALE_XOTHERM,
ADC_SCALE_NONE,
};
/**
* struct pm8xxx_adc_linear_graph - Represent ADC characteristics
* @dy: Numerator slope to calculate the gain
* @dx: Denominator slope to calculate the gain
* @adc_vref: A/D word of the voltage reference used for the channel
* @adc_gnd: A/D word of the ground reference used for the channel
*
* Each ADC device has different offset and gain parameters which are computed
* to calibrate the device.
*/
struct pm8xxx_adc_linear_graph {
int64_t dy;
int64_t dx;
int64_t adc_vref;
int64_t adc_gnd;
};
/**
* struct pm8xxx_adc_map_pt - Map the graph representation for ADC channel
* @x: Represent the ADC digitized code
* @y: Represent the physical data which can be temperature, voltage,
* resistance
*/
struct pm8xxx_adc_map_pt {
int32_t x;
int32_t y;
};
/**
* struct pm8xxx_adc_scaling_ratio - Represent scaling ratio for adc input
* @num: Numerator scaling parameter
* @den: Denominator scaling parameter
*/
struct pm8xxx_adc_scaling_ratio {
int32_t num;
int32_t den;
};
/**
* struct pm8xxx_adc_properties - Represent the ADC properties
* @adc_reference: Reference voltage for PM8XXX ADC
* @bitresolution: ADC bit resolution for PM8XXX ADC
* @biploar: Polarity for PM8XXX ADC
*/
struct pm8xxx_adc_properties {
uint32_t adc_vdd_reference;
uint32_t bitresolution;
bool bipolar;
};
/**
* struct pm8xxx_adc_chan_properties - Represent channel properties of the ADC
* @offset_gain_numerator: The inverse numerator of the gain applied to the
* input channel
* @offset_gain_denominator: The inverse denominator of the gain applied to the
* input channel
* @adc_graph: ADC graph for the channel of struct type pm8xxx_adc_linear_graph
*/
struct pm8xxx_adc_chan_properties {
uint32_t offset_gain_numerator;
uint32_t offset_gain_denominator;
struct pm8xxx_adc_linear_graph adc_graph[2];
};
/**
* struct pm8xxx_adc_chan_result - Represent the result of the PM8XXX ADC
* @chan: The channel number of the requested conversion
* @adc_code: The pre-calibrated digital output of a given ADC relative to the
* the ADC reference
* @measurement: In units specific for a given ADC; most ADC uses reference
* voltage but some ADC uses reference current. This measurement
* here is a number relative to a reference of a given ADC
* @physical: The data meaningful for each individual channel whether it is
* voltage, current, temperature, etc.
* All voltage units are represented in micro - volts.
* -Battery temperature units are represented as 0.1 DegC
* -PA Therm temperature units are represented as DegC
* -PMIC Die temperature units are represented as 0.001 DegC
*/
struct pm8xxx_adc_chan_result {
uint32_t chan;
int32_t adc_code;
int64_t measurement;
int64_t physical;
};
#if defined(CONFIG_SENSORS_PM8XXX_ADC) \
|| defined(CONFIG_SENSORS_PM8XXX_ADC_MODULE)
/**
* pm8xxx_adc_scale_default() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
* @chan_prop: individual channel properties to compensate the i/p scaling,
* slope and offset.
* @chan_rslt: Physical result to be stored.
*/
int32_t pm8xxx_adc_scale_default(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt);
/**
* pm8xxx_adc_scale_tdkntcg_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature of the xo therm in mili
degC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
* @chan_prop: individual channel properties to compensate the i/p scaling,
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
int32_t pm8xxx_adc_tdkntcg_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt);
/**
* pm8xxx_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in degC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
* @chan_prop: individual channel properties to compensate the i/p scaling,
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
int32_t pm8xxx_adc_scale_batt_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt);
/**
* pm8xxx_adc_scale_pa_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in degC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
* @chan_prop: individual channel properties to compensate the i/p scaling,
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
int32_t pm8xxx_adc_scale_pa_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt);
/**
* pm8xxx_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Performs the AMUX out as 2mv/K and returns
* the temperature in mili degC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
* @chan_prop: individual channel properties to compensate the i/p scaling,
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
int32_t pm8xxx_adc_scale_pmic_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt);
/**
* pm8xxx_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
* @chan_prop: individual channel properties to compensate the i/p scaling,
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt);
#else
static inline int32_t pm8xxx_adc_scale_default(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t pm8xxx_adc_tdkntcg_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t pm8xxx_adc_scale_batt_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t pm8xxx_adc_scale_pa_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t pm8xxx_adc_scale_pmic_therm(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop,
struct pm8xxx_adc_chan_result *chan_rslt)
{ return -ENXIO; }
#endif
/**
* struct pm8xxx_adc_scale_fn - Scaling function prototype
* @chan: Function pointer to one of the scaling functions
* which takes the adc properties, channel properties,
* and returns the physical result
*/
struct pm8xxx_adc_scale_fn {
int32_t (*chan) (int32_t,
const struct pm8xxx_adc_properties *,
const struct pm8xxx_adc_chan_properties *,
struct pm8xxx_adc_chan_result *);
};
/**
* struct pm8xxx_adc_amux - AMUX properties for individual channel
* @name: Channel name
* @channel_name: Channel in integer used from pm8xxx_adc_channels
* @chan_path_prescaling: Channel scaling performed on the input signal
* @adc_rsv: Input reference Voltage/GND selection to the ADC
* @adc_decimation: Sampling rate desired for the channel
* adc_scale_fn: Scaling function to convert to the data meaningful for
* each individual channel whether it is voltage, current,
* temperature, etc and compensates the channel properties
*/
struct pm8xxx_adc_amux {
char *name;
enum pm8xxx_adc_channels channel_name;
enum pm8xxx_adc_channel_scaling_param chan_path_prescaling;
enum pm8xxx_adc_amux_input_rsv adc_rsv;
enum pm8xxx_adc_decimation_type adc_decimation;
enum pm8xxx_adc_scale_fn_type adc_scale_fn;
};
/**
* struct pm8xxx_adc_arb_btm_param - PM8XXX ADC BTM parameters to set threshold
* temperature for client notification
* @low_thr_temp: low temperature threshold request for notification
* @high_thr_temp: high temperature threshold request for notification
* @low_thr_voltage: low temperature converted to voltage by arbiter driver
* @high_thr_voltage: high temperature converted to voltage by arbiter driver
* @interval: Interval period to check for temperature notification
* @btm_warm_fn: Remote function call for warm threshold.
* @btm_cool_fn: Remote function call for cold threshold.
*
* BTM client passes the parameters to be set for the
* temperature threshold notifications. The client is
* responsible for setting the new threshold
* levels once the thresholds are reached
*/
struct pm8xxx_adc_arb_btm_param {
int32_t low_thr_temp;
int32_t high_thr_temp;
uint64_t low_thr_voltage;
uint64_t high_thr_voltage;
int32_t interval;
void (*btm_warm_fn) (bool);
void (*btm_cool_fn) (bool);
};
int32_t pm8xxx_adc_batt_scaler(struct pm8xxx_adc_arb_btm_param *,
const struct pm8xxx_adc_properties *adc_prop,
const struct pm8xxx_adc_chan_properties *chan_prop);
/**
* struct pm8xxx_adc_platform_data - PM8XXX ADC platform data
* @adc_prop: ADC specific parameters, voltage and channel setup
* @adc_channel: Channel properties of the ADC arbiter
* @adc_num_board_channel: Number of channels added in the board file
* @adc_mpp_base: PM8XXX MPP0 base passed from board file. This is used
* to offset the PM8XXX MPP passed to configure the
* the MPP to AMUX mapping.
*/
struct pm8xxx_adc_platform_data {
struct pm8xxx_adc_properties *adc_prop;
struct pm8xxx_adc_amux *adc_channel;
uint32_t adc_num_board_channel;
uint32_t adc_mpp_base;
};
/* Public API */
#if defined(CONFIG_SENSORS_PM8XXX_ADC) \
|| defined(CONFIG_SENSORS_PM8XXX_ADC_MODULE)
/**
* pm8xxx_adc_read() - Performs ADC read on the channel.
* @channel: Input channel to perform the ADC read.
* @result: Structure pointer of type adc_chan_result
* in which the ADC read results are stored.
*/
uint32_t pm8xxx_adc_read(enum pm8xxx_adc_channels channel,
struct pm8xxx_adc_chan_result *result);
/**
* pm8xxx_adc_mpp_config_read() - Configure's the PM8XXX MPP
* to AMUX6 and performs an ADC read.
*
* On PM8921 ADC the MPP needs to first be configured
* as an analog input to the AMUX pre-mux channel before
* issuing a read request. PM8921 MPP 8 is mapped to AMUX8
* and is common between remote processor's.
*
* On PM8018 ADC the MPP is directly connected to the AMUX
* pre-mux. Therefore clients of the PM8018 MPP do not need
* to configure the MPP as an analog input to the pre-mux.
* Clients can directly issue request on the pre-mux AMUX
* channel to read the ADC on the MPP. Clients can directly
* call the pm8xxx_adc_read().
* @mpp_num PM8XXX MPP number to configure to AMUX6.
* @channel: Input channel to perform the ADC read.
* a) 'ADC_MPP_1_AMUX6' if the input voltage is less than 1.8V
* b) 'ADC_MPP_2_AMUX6' if the input voltage is greater then 1.8V
* the input voltage is pre-divided by 3 and passed to the ADC.
* The appropriate scaling function needs to be selected to let
* the driver know a post scaling is required before returning
* the result.
* @result: Structure pointer of type adc_chan_result
* in which the ADC read results are stored.
*/
uint32_t pm8xxx_adc_mpp_config_read(uint32_t mpp_num,
enum pm8xxx_adc_channels channel,
struct pm8xxx_adc_chan_result *result);
/**
* pm8xxx_adc_btm_start() - Configure the BTM registers and start
monitoring the BATT_THERM channel for
threshold warm/cold temperature set
by the Battery client. The btm_start
api is to be used after calling the
pm8xxx_btm_configure() api which sets
the temperature thresholds, interval
and functions to call when warm/cold
events are triggered.
* @param: none.
*/
uint32_t pm8xxx_adc_btm_start(void);
/**
* pm8xxx_adc_btm_end() - Configures the BTM registers to stop
* monitoring the BATT_THERM channel for
* warm/cold events and disables the
* interval timer.
* @param: none.
*/
uint32_t pm8xxx_adc_btm_end(void);
/**
* pm8xxx_adc_btm_configure() - Configures the BATT_THERM channel
* parameters for warm/cold thresholds.
* Sets the interval timer for perfoming
* reading the temperature done by the HW.
* @btm_param: Structure pointer of type adc_arb_btm_param *
* which client provides for threshold warm/cold,
* interval and functions to call when warm/cold
* events are triggered.
*/
uint32_t pm8xxx_adc_btm_configure(struct pm8xxx_adc_arb_btm_param *);
#else
static inline uint32_t pm8xxx_adc_read(uint32_t channel,
struct pm8xxx_adc_chan_result *result)
{ return -ENXIO; }
static inline uint32_t pm8xxx_adc_mpp_config_read(uint32_t mpp_num,
enum pm8xxx_adc_channels channel,
struct pm8xxx_adc_chan_result *result)
{ return -ENXIO; }
static inline uint32_t pm8xxx_adc_btm_start(void)
{ return -ENXIO; }
static inline uint32_t pm8xxx_adc_btm_end(void)
{ return -ENXIO; }
static inline uint32_t pm8xxx_adc_btm_configure(
struct pm8xxx_adc_arb_btm_param *param)
{ return -ENXIO; }
#endif
#endif /* PM8XXX_ADC_H */