hwmon: Add MSM adc driver

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
Stephen Boyd 2013-01-11 16:42:58 -08:00
parent 1eaf2cb162
commit 1d3a4b012c
8 changed files with 2540 additions and 0 deletions

View file

@ -838,6 +838,19 @@ config SENSORS_NTC_THERMISTOR
This driver can also be built as a module. If so, the module
will be called ntc-thermistor.
config SENSORS_MSM_ADC
tristate "MSM ADC Driver for current measurement"
depends on ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_FSM9XXX || ARCH_MSM7X27A
default n
help
Provides interface for measuring the ADC's on AMUX channels of XOADC,
MPP's and the XOTHERM on pmic8058 for msm8x60 and provides post processing
of the channel for the ADC Raw Data. For reading LTC and EPM ADC channels
say yes here to include support for measuring current in real-time
from various power-rails on the Fluid board. The ADC circuit
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_PC87360
tristate "National Semiconductor PC87360 family"
depends on !PPC

View file

@ -127,6 +127,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
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_PMBUS) += pmbus/

469
drivers/hwmon/m_adcproc.c Normal file
View file

@ -0,0 +1,469 @@
/* Copyright (c) 2010-2011, Code Aurora Forum. 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/msm_adc.h>
#define KELVINMIL_DEGMIL 273160
static const struct adc_map_pt adcmap_batttherm[] = {
{2020, -30},
{1923, -20},
{1796, -10},
{1640, 0},
{1459, 10},
{1260, 20},
{1159, 25},
{1059, 30},
{871, 40},
{706, 50},
{567, 60},
{453, 70},
{364, 80}
};
static const struct adc_map_pt adcmap_msmtherm[] = {
{2150, -30},
{2107, -20},
{2037, -10},
{1929, 0},
{1776, 10},
{1579, 20},
{1467, 25},
{1349, 30},
{1108, 40},
{878, 50},
{677, 60},
{513, 70},
{385, 80},
{287, 90},
{215, 100},
{186, 110},
{107, 120}
};
static const struct adc_map_pt adcmap_ntcg104ef104fb[] = {
{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
adc_map_linear(const struct 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;
}
int32_t scale_default(int32_t adc_code,
const struct adc_properties *adc_properties,
const struct chan_properties *chan_properties,
struct adc_chan_result *adc_chan_result)
{
bool negative_rawfromoffset = 0;
int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
if (!chan_properties->gain_numerator ||
!chan_properties->gain_denominator)
return -EINVAL;
adc_chan_result->adc_code = adc_code;
if (rawfromoffset < 0) {
if (adc_properties->bipolar) {
rawfromoffset = (rawfromoffset ^ -1) + 1;
negative_rawfromoffset = 1;
} else
rawfromoffset = 0;
}
if (rawfromoffset >= 1 << adc_properties->bitresolution)
rawfromoffset = (1 << adc_properties->bitresolution) - 1;
adc_chan_result->measurement = (int64_t)rawfromoffset*
chan_properties->adc_graph->dx*
chan_properties->gain_denominator;
/* do_div only perform positive integer division! */
do_div(adc_chan_result->measurement, chan_properties->adc_graph->dy*
chan_properties->gain_numerator);
if (negative_rawfromoffset)
adc_chan_result->measurement =
(adc_chan_result->measurement ^ -1) + 1;
/* 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 = (int32_t) adc_chan_result->measurement;
return 0;
}
int32_t scale_batt_therm(int32_t adc_code,
const struct adc_properties *adc_properties,
const struct chan_properties *chan_properties,
struct adc_chan_result *adc_chan_result)
{
scale_default(adc_code, adc_properties, chan_properties,
adc_chan_result);
/* convert mV ---> degC using the table */
return adc_map_linear(
adcmap_batttherm,
sizeof(adcmap_batttherm)/sizeof(adcmap_batttherm[0]),
adc_chan_result->physical,
&adc_chan_result->physical);
}
int32_t scale_msm_therm(int32_t adc_code,
const struct adc_properties *adc_properties,
const struct chan_properties *chan_properties,
struct adc_chan_result *adc_chan_result)
{
scale_default(adc_code, adc_properties, chan_properties,
adc_chan_result);
/* convert mV ---> degC using the table */
return adc_map_linear(
adcmap_msmtherm,
sizeof(adcmap_msmtherm)/sizeof(adcmap_msmtherm[0]),
adc_chan_result->physical,
&adc_chan_result->physical);
}
int32_t scale_pmic_therm(int32_t adc_code,
const struct adc_properties *adc_properties,
const struct chan_properties *chan_properties,
struct adc_chan_result *adc_chan_result)
{
/* 2mV/K */
int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
if (!chan_properties->gain_numerator ||
!chan_properties->gain_denominator)
return -EINVAL;
adc_chan_result->adc_code = adc_code;
if (rawfromoffset > 0) {
if (rawfromoffset >= 1 << adc_properties->bitresolution)
rawfromoffset = (1 << adc_properties->bitresolution)
- 1;
adc_chan_result->measurement = (int64_t)rawfromoffset*
chan_properties->adc_graph->dx*
chan_properties->gain_denominator*1000;
do_div(adc_chan_result->measurement,
chan_properties->adc_graph->dy*
chan_properties->gain_numerator*2);
} else {
adc_chan_result->measurement = 0;
}
/* Note: adc_chan_result->measurement is in the unit of
adc_properties.adc_reference */
adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
/* Change to .001 deg C */
adc_chan_result->physical -= KELVINMIL_DEGMIL;
adc_chan_result->measurement <<= 1;
return 0;
}
/* Scales the ADC code to 0.001 degrees C using the map
* table for the XO thermistor.
*/
int32_t tdkntcgtherm(int32_t adc_code,
const struct adc_properties *adc_properties,
const struct chan_properties *chan_properties,
struct adc_chan_result *adc_chan_result)
{
int32_t offset = chan_properties->adc_graph->offset,
dy = chan_properties->adc_graph->dy,
dx = chan_properties->adc_graph->dx,
fullscale_calibrated_adc_code;
uint32_t rt_r25;
uint32_t num1, num2, denom;
adc_chan_result->adc_code = adc_code;
fullscale_calibrated_adc_code = dy + offset;
/* The above is a short cut in math that would reduce a lot of
computation whereas the below expression
(adc_properties->adc_reference*dy+dx*offset+(dx>>1))/dx
is a more generic formula when the 2 reference voltages are
different than 0 and full scale voltage. */
if ((dy == 0) || (dx == 0) ||
(offset >= fullscale_calibrated_adc_code)) {
return -EINVAL;
} else {
if (adc_code >= fullscale_calibrated_adc_code) {
rt_r25 = (uint32_t)-1;
} else if (adc_code <= offset) {
rt_r25 = 0;
} else {
/* The formula used is (adc_code of current reading - offset)/
* (the calibrated fullscale adc code - adc_code of current reading).
* For this channel, at this time, chan_properties->gain_numerator =
* chan_properties->gain_denominator = 1, so no need to incorporate
* into the formula even though we could and multiply/divide by 1
* which yields the same result but expensive on computation. */
num1 = (adc_code - offset) << 14;
num2 = (fullscale_calibrated_adc_code - adc_code) >> 1;
denom = fullscale_calibrated_adc_code - adc_code;
if ((int)denom <= 0)
rt_r25 = 0x7FFFFFFF;
else
rt_r25 = (num1 + num2) / denom;
}
if (rt_r25 > 0x7FFFFFFF)
rt_r25 = 0x7FFFFFFF;
adc_map_linear(adcmap_ntcg104ef104fb,
sizeof(adcmap_ntcg104ef104fb)/sizeof(adcmap_ntcg104ef104fb[0]),
(int32_t)rt_r25, &adc_chan_result->physical);
}
return 0;
}
int32_t scale_xtern_chgr_cur(int32_t adc_code,
const struct adc_properties *adc_properties,
const struct chan_properties *chan_properties,
struct adc_chan_result *adc_chan_result)
{
int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
if (!chan_properties->gain_numerator ||
!chan_properties->gain_denominator)
return -EINVAL;
adc_chan_result->adc_code = adc_code;
if (rawfromoffset > 0) {
if (rawfromoffset >= 1 << adc_properties->bitresolution)
rawfromoffset = (1 << adc_properties->bitresolution)
- 1;
adc_chan_result->measurement = ((int64_t)rawfromoffset * 5)*
chan_properties->adc_graph->dx*
chan_properties->gain_denominator;
do_div(adc_chan_result->measurement,
chan_properties->adc_graph->dy*
chan_properties->gain_numerator);
} else {
adc_chan_result->measurement = 0;
}
adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
return 0;
}

1533
drivers/hwmon/msm_adc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -256,6 +256,7 @@ header-y += mroute.h
header-y += mroute6.h
header-y += msdos_fs.h
header-y += msg.h
header-y += msm_adc.h
header-y += mtio.h
header-y += n_r3964.h
header-y += nbd.h

30
include/linux/m_adcproc.h Normal file
View file

@ -0,0 +1,30 @@
/* Copyright (c) 2010-2011, Code Aurora Forum. 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.
*
*/
#ifndef _M_ADC_PROC_H
#define _M_ADC_PROC_H
#include <linux/msm_adc.h>
int32_t tdkntcgtherm(int32_t adc_code, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
int32_t scale_default(int32_t adc_code, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
int32_t scale_msm_therm(int32_t adc_code, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
int32_t scale_batt_therm(int32_t adc_code, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
int32_t scale_pmic_therm(int32_t adc_code, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
int32_t scale_xtern_chgr_cur(int32_t adc_code, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
#endif /* _M_ADC_PROC_H */

372
include/linux/msm_adc.h Normal file
View file

@ -0,0 +1,372 @@
#ifndef __MSM_ADC_H
#define __MSM_ADC_H
#include <linux/sched.h>
#define MSM_ADC_MAX_CHAN_STR 64
/* must be <= to the max buffer size in the modem implementation */
#define MSM_ADC_DEV_MAX_INFLIGHT 9
#define MSM_ADC_IOCTL_CODE 0x90
struct msm_adc_conversion {
/* hwmon channel number - this is not equivalent to the DAL chan */
uint32_t chan;
/* returned result in ms */
int result;
};
struct adc_chan_result {
/* The channel number of the requesting/requested conversion */
uint32_t chan;
/* The pre-calibrated digital output of a given ADC relative to the
ADC reference */
int32_t adc_code;
/* 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 */
int64_t measurement;
/* The data meaningful for each individual channel whether it is
* voltage, current, temperature, etc. */
int64_t physical;
};
/*
* Issue a blocking adc conversion request. Once the call returns, the data
* can be found in the 'physical' field of adc_chan_result. This call will
* return ENODATA if there is an invalid result returned by the modem driver.
*/
#define MSM_ADC_REQUEST _IOWR(MSM_ADC_IOCTL_CODE, 1, \
struct adc_chan_result)
/*
* Issue a non-blocking adc conversion request. The results from this
* request can be obtained by calling AIO_READ once the transfer is
* completed. To verify completion, the blocking call AIO_POLL can be used.
* If there are no slot resources, this call will return an error with errno
* set to EWOULDBLOCK.
*/
#define MSM_ADC_AIO_REQUEST _IOWR(MSM_ADC_IOCTL_CODE, 2, \
struct adc_chan_result)
/*
* Same non-blocking semantics as AIO_REQUEST, except this call will block
* if there are no available slot resources. This call can fail with errno
* set to EDEADLK if there are no resources and the file descriptor in question
* has outstanding conversion requests already. This is done so the client
* does not block on resources that can only be freed by reading the results --
* effectively deadlocking the system. In this case, the client must read
* pending results before proceeding to free up resources.
*/
#define MSM_ADC_AIO_REQUEST_BLOCK_RES _IOWR(MSM_ADC_IOCTL_CODE, 3, \
struct adc_chan_result)
/*
* Returns the number of pending results that are associated with a particular
* file descriptor. If there are no pending results, this call will block until
* there is at least one. If there are no requests queued at all on this file
* descriptor, this call will fail with EDEADLK. This is to prevent deadlock in
* a single-threaded scenario where POLL would never return.
*/
#define MSM_ADC_AIO_POLL _IOR(MSM_ADC_IOCTL_CODE, 4, \
uint32_t)
#define MSM_ADC_FLUID_INIT _IOR(MSM_ADC_IOCTL_CODE, 5, \
uint32_t)
#define MSM_ADC_FLUID_DEINIT _IOR(MSM_ADC_IOCTL_CODE, 6, \
uint32_t)
struct msm_adc_aio_result {
uint32_t chan;
int result;
};
/*
* Read the results from an AIO / non-blocking conversion request. AIO_POLL
* should be used before using this command to verify how many pending requests
* are available for the file descriptor. This call will fail with errno set to
* ENOMSG if there are no pending messages to be read at the time of the call.
* The call will return ENODATA if there is an invalid result returned by the
* modem driver.
*/
#define MSM_ADC_AIO_READ _IOR(MSM_ADC_IOCTL_CODE, 5, \
struct adc_chan_result)
struct msm_adc_lookup {
/* channel name (input) */
char name[MSM_ADC_MAX_CHAN_STR];
/* local channel index (output) */
uint32_t chan_idx;
};
/*
* Look up a channel name and get back an index that can be used
* as a parameter to the conversion request commands.
*/
#define MSM_ADC_LOOKUP _IOWR(MSM_ADC_IOCTL_CODE, 6, \
struct msm_adc_lookup)
#ifdef __KERNEL__
#define MSM_ADC_MAX_NUM_DEVS 3
enum {
ADC_CONFIG_TYPE1,
ADC_CONFIG_TYPE2,
ADC_CONFIG_NONE = 0xffffffff
};
enum {
ADC_CALIB_CONFIG_TYPE1,
ADC_CALIB_CONFIG_TYPE2,
ADC_CALIB_CONFIG_TYPE3,
ADC_CALIB_CONFIG_TYPE4,
ADC_CALIB_CONFIG_TYPE5,
ADC_CALIB_CONFIG_TYPE6,
ADC_CALIB_CONFIG_TYPE7,
ADC_CALIB_CONFIG_NONE = 0xffffffff
};
enum {
/* CHAN_PATH_TYPEn is specific for each ADC driver
and can be used however way it wants*/
CHAN_PATH_TYPE1,
CHAN_PATH_TYPE2,
CHAN_PATH_TYPE3,
CHAN_PATH_TYPE4,
CHAN_PATH_TYPE5,
CHAN_PATH_TYPE6,
CHAN_PATH_TYPE7,
CHAN_PATH_TYPE8,
CHAN_PATH_TYPE9,
CHAN_PATH_TYPE10,
CHAN_PATH_TYPE11,
CHAN_PATH_TYPE12,
CHAN_PATH_TYPE13,
CHAN_PATH_TYPE14,
CHAN_PATH_TYPE15,
CHAN_PATH_TYPE16,
/* A given channel connects directly to the ADC */
CHAN_PATH_TYPE_NONE = 0xffffffff
};
#define CHANNEL_ADC_BATT_ID 0
#define CHANNEL_ADC_BATT_THERM 1
#define CHANNEL_ADC_BATT_AMON 2
#define CHANNEL_ADC_VBATT 3
#define CHANNEL_ADC_VCOIN 4
#define CHANNEL_ADC_VCHG 5
#define CHANNEL_ADC_CHG_MONITOR 6
#define CHANNEL_ADC_VPH_PWR 7
#define CHANNEL_ADC_USB_VBUS 8
#define CHANNEL_ADC_DIE_TEMP 9
#define CHANNEL_ADC_DIE_TEMP_4K 0xa
#define CHANNEL_ADC_XOTHERM 0xb
#define CHANNEL_ADC_XOTHERM_4K 0xc
#define CHANNEL_ADC_HDSET 0xd
#define CHANNEL_ADC_MSM_THERM 0xe
#define CHANNEL_ADC_625_REF 0xf
#define CHANNEL_ADC_1250_REF 0x10
#define CHANNEL_ADC_325_REF 0x11
#define CHANNEL_ADC_FSM_THERM 0x12
#define CHANNEL_ADC_PA_THERM 0x13
enum {
CALIB_STARTED,
CALIB_NOT_REQUIRED = 0xffffffff,
};
struct linear_graph {
int32_t offset;
int32_t dy; /* Slope numerator */
int32_t dx; /* Slope denominator */
};
struct adc_map_pt {
int32_t x;
int32_t y;
};
struct adc_properties {
uint32_t adc_reference; /* milli-voltage for this adc */
uint32_t bitresolution;
bool bipolar;
uint32_t conversiontime;
};
struct chan_properties {
uint32_t gain_numerator;
uint32_t gain_denominator;
struct linear_graph *adc_graph;
/* this maybe the same as adc_properties.ConversionTime
if channel does not change the adc properties */
uint32_t chan_conv_time;
};
struct msm_adc_channels {
char *name;
uint32_t channel_name;
uint32_t adc_dev_instance;
struct adc_access_fn *adc_access_fn;
uint32_t chan_path_type;
uint32_t adc_config_type;
uint32_t adc_calib_type;
int32_t (*chan_processor)(int32_t, const struct adc_properties *,
const struct chan_properties *, struct adc_chan_result *);
};
struct msm_adc_platform_data {
struct msm_adc_channels *channel;
uint32_t num_chan_supported;
uint32_t num_adc;
uint32_t chan_per_adc;
char **dev_names;
uint32_t target_hw;
uint32_t gpio_config;
u32 (*adc_gpio_enable) (int);
u32 (*adc_gpio_disable) (int);
u32 (*adc_fluid_enable) (void);
u32 (*adc_fluid_disable) (void);
};
enum hw_type {
MSM_7x30,
MSM_8x60,
FSM_9xxx,
MSM_8x25,
};
enum epm_gpio_config {
MPROC_CONFIG,
APROC_CONFIG
};
enum adc_request {
START_OF_CONV,
END_OF_CONV,
START_OF_CALIBRATION,
END_OF_CALIBRATION,
};
struct adc_dev_spec {
uint32_t hwmon_dev_idx;
struct dal_dev_spec {
uint32_t dev_idx;
uint32_t chan_idx;
} dal;
};
struct dal_conv_request {
struct dal_dev_spec target;
void *cb_h;
};
struct dal_adc_result {
uint32_t status;
uint32_t token;
uint32_t dev_idx;
uint32_t chan_idx;
int physical;
uint32_t percent;
uint32_t microvolts;
uint32_t reserved;
};
struct dal_conv_slot {
void *cb_h;
struct dal_adc_result result;
struct completion comp;
struct list_head list;
uint32_t idx;
uint32_t chan_idx;
bool blocking;
struct msm_client_data *client;
};
struct dal_translation {
uint32_t dal_dev_idx;
uint32_t hwmon_dev_idx;
uint32_t hwmon_start;
uint32_t hwmon_end;
};
struct msm_client_data {
struct list_head complete_list;
bool online;
int32_t adc_chan;
uint32_t num_complete;
uint32_t num_outstanding;
wait_queue_head_t data_wait;
wait_queue_head_t outst_wait;
struct mutex lock;
};
struct adc_conv_slot {
void *cb_h;
union {
struct adc_chan_result result;
struct dal_adc_result dal_result;
} conv;
struct completion comp;
struct completion *compk;
struct list_head list;
uint32_t idx;
enum adc_request adc_request;
bool blocking;
struct msm_client_data *client;
struct work_struct work;
struct chan_properties chan_properties;
uint32_t chan_path;
uint32_t chan_adc_config;
uint32_t chan_adc_calib;
};
struct adc_access_fn {
int32_t (*adc_select_chan_and_start_conv)(uint32_t,
struct adc_conv_slot*);
int32_t (*adc_read_adc_code)(uint32_t dev_instance, int32_t *data);
struct adc_properties *(*adc_get_properties)(uint32_t dev_instance);
void (*adc_slot_request)(uint32_t dev_instance,
struct adc_conv_slot **);
void (*adc_restore_slot)(uint32_t dev_instance,
struct adc_conv_slot *slot);
int32_t (*adc_calibrate)(uint32_t dev_instance, struct adc_conv_slot*,
int *);
};
void msm_adc_wq_work(struct work_struct *work);
void msm_adc_conv_cb(void *context, u32 param, void *evt_buf, u32 len);
#ifdef CONFIG_SENSORS_MSM_ADC
int32_t adc_channel_open(uint32_t channel, void **h);
int32_t adc_channel_close(void *h);
int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt);
int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result);
#else
static inline int32_t adc_channel_open(uint32_t channel, void **h)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
static inline int32_t adc_channel_close(void *h)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
static inline int32_t
adc_channel_request_conv(void *h, struct completion *conv_complete_evt)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
static inline int32_t
adc_channel_read_result(void *h, struct adc_chan_result *chan_result)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
#endif /* CONFIG_SENSORS_MSM_ADC */
#endif
#endif /* __MSM_ADC_H */

View file

@ -0,0 +1,121 @@
/* Copyright (c) 2010-2011, Code Aurora Forum. 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 XOADC Driver header file
*/
#ifndef _PMIC8058_XOADC_H_
#define _PMIC8058_XOADC_H_
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/workqueue.h>
struct xoadc_conv_state {
struct adc_conv_slot *context;
struct list_head slots;
struct mutex list_lock;
};
#define CHANNEL_VCOIN 0
#define CHANNEL_VBAT 1
#define CHANNEL_VCHG 2
#define CHANNEL_CHG_MONITOR 3
#define CHANNEL_VPH_PWR 4
#define CHANNEL_MPP5 5
#define CHANNEL_MPP6 6
#define CHANNEL_MPP7 7
#define CHANNEL_MPP8 8
#define CHANNEL_MPP9 9
#define CHANNEL_USB_VBUS 0Xa
#define CHANNEL_DIE_TEMP 0Xb
#define CHANNEL_INTERNAL 0xc
#define CHANNEL_125V 0xd
#define CHANNEL_INTERNAL_2 0Xe
#define CHANNEL_MUXOFF 0xf
#define XOADC_MPP_3 0x2
#define XOADC_MPP_4 0X3
#define XOADC_MPP_5 0x4
#define XOADC_MPP_7 0x6
#define XOADC_MPP_8 0x7
#define XOADC_MPP_10 0X9
#define XOADC_PMIC_0 0x0
#define CHANNEL_ADC_625_MV 625
struct xoadc_platform_data {
struct adc_properties *xoadc_prop;
u32 (*xoadc_setup) (void);
void (*xoadc_shutdown) (void);
void (*xoadc_mpp_config) (void);
int (*xoadc_vreg_set) (int);
int (*xoadc_vreg_setup) (void);
void (*xoadc_vreg_shutdown) (void);
u32 xoadc_num;
u32 xoadc_wakeup;
};
#ifdef CONFIG_PMIC8058_XOADC
int32_t pm8058_xoadc_read_adc_code(uint32_t adc_instance, int32_t *data);
int32_t pm8058_xoadc_select_chan_and_start_conv(uint32_t adc_instance,
struct adc_conv_slot *slot);
void pm8058_xoadc_slot_request(uint32_t adc_instance,
struct adc_conv_slot **slot);
void pm8058_xoadc_restore_slot(uint32_t adc_instance,
struct adc_conv_slot *slot);
struct adc_properties *pm8058_xoadc_get_properties(uint32_t dev_instance);
int32_t pm8058_xoadc_calibrate(uint32_t dev_instance,
struct adc_conv_slot *slot, int * calib_status);
int32_t pm8058_xoadc_registered(void);
int32_t pm8058_xoadc_calib_device(uint32_t adc_instance);
#else
static inline int32_t pm8058_xoadc_read_adc_code(uint32_t adc_instance,
int32_t *data)
{ return -ENXIO; }
static inline int32_t pm8058_xoadc_select_chan_and_start_conv(
uint32_t adc_instance, struct adc_conv_slot *slot)
{ return -ENXIO; }
static inline void pm8058_xoadc_slot_request(uint32_t adc_instance,
struct adc_conv_slot **slot)
{ return; }
static inline void pm8058_xoadc_restore_slot(uint32_t adc_instance,
struct adc_conv_slot *slot)
{ return; }
static inline struct adc_properties *pm8058_xoadc_get_properties(
uint32_t dev_instance)
{ return NULL; }
static inline int32_t pm8058_xoadc_calibrate(uint32_t dev_instance,
struct adc_conv_slot *slot, int *calib_status)
{ return -ENXIO; }
static inline int32_t pm8058_xoadc_registered(void)
{ return -ENXIO; }
static inline int32_t pm8058_xoadc_calib_device(uint32_t adc_instance)
{ return -ENXIO; }
#endif
#endif