1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333 |
- /*
- * Copyright (c) 2011-2013, 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's PM8921/PM8018 ADC Arbiter driver
- */
- #define pr_fmt(fmt) "%s: " fmt, __func__
- #include <linux/kernel.h>
- #include <linux/err.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/mutex.h>
- #include <linux/hwmon.h>
- #include <linux/module.h>
- #include <linux/debugfs.h>
- #include <linux/interrupt.h>
- #include <linux/completion.h>
- #include <linux/hwmon-sysfs.h>
- #include <linux/mfd/pm8xxx/mpp.h>
- #include <linux/platform_device.h>
- #include <linux/mfd/pm8xxx/core.h>
- #include <linux/regulator/consumer.h>
- #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
- #include <mach/msm_xo.h>
- /* User Bank register set */
- #define PM8XXX_ADC_ARB_USRP_CNTRL1 0x197
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB BIT(0)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV1 BIT(1)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV2 BIT(2)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV3 BIT(3)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV4 BIT(4)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV5 BIT(5)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_EOC BIT(6)
- #define PM8XXX_ADC_ARB_USRP_CNTRL1_REQ BIT(7)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL 0x198
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_RSV0 BIT(0)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_RSV1 BIT(1)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_PREMUX0 BIT(2)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_PREMUX1 BIT(3)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL0 BIT(4)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL1 BIT(5)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL2 BIT(6)
- #define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL3 BIT(7)
- #define PM8XXX_ADC_ARB_USRP_ANA_PARAM 0x199
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM 0x19A
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 BIT(0)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 BIT(1)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_CLK_RATE0 BIT(2)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_CLK_RATE1 BIT(3)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_EOC BIT(4)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0 BIT(5)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1 BIT(6)
- #define PM8XXX_ADC_ARB_USRP_DIG_PARAM_EN BIT(7)
- #define PM8XXX_ADC_ARB_USRP_RSV 0x19B
- #define PM8XXX_ADC_ARB_USRP_RSV_RST BIT(0)
- #define PM8XXX_ADC_ARB_USRP_RSV_DTEST0 BIT(1)
- #define PM8XXX_ADC_ARB_USRP_RSV_DTEST1 BIT(2)
- #define PM8XXX_ADC_ARB_USRP_RSV_OP BIT(3)
- #define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL0 BIT(4)
- #define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL1 BIT(5)
- #define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL2 BIT(6)
- #define PM8XXX_ADC_ARB_USRP_RSV_TRM BIT(7)
- #define PM8XXX_ADC_ARB_USRP_DATA0 0x19D
- #define PM8XXX_ADC_ARB_USRP_DATA1 0x19C
- #define PM8XXX_ADC_ARB_BTM_CNTRL1 0x17e
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_EN_BTM BIT(0)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE BIT(1)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1 BIT(2)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2 BIT(3)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3 BIT(4)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4 BIT(5)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_EOC BIT(6)
- #define PM8XXX_ADC_ARB_BTM_CNTRL1_REQ BIT(7)
- #define PM8XXX_ADC_ARB_BTM_CNTRL2 0x18c
- #define PM8XXX_ADC_ARB_BTM_AMUX_CNTRL 0x17f
- #define PM8XXX_ADC_ARB_BTM_ANA_PARAM 0x180
- #define PM8XXX_ADC_ARB_BTM_DIG_PARAM 0x181
- #define PM8XXX_ADC_ARB_BTM_RSV 0x182
- #define PM8XXX_ADC_ARB_BTM_DATA1 0x183
- #define PM8XXX_ADC_ARB_BTM_DATA0 0x184
- #define PM8XXX_ADC_ARB_BTM_BAT_COOL_THR1 0x185
- #define PM8XXX_ADC_ARB_BTM_BAT_COOL_THR0 0x186
- #define PM8XXX_ADC_ARB_BTM_BAT_WARM_THR1 0x187
- #define PM8XXX_ADC_ARB_BTM_BAT_WARM_THR0 0x188
- #define PM8XXX_ADC_ARB_ANA_DIG 0xa0
- #define PM8XXX_ADC_BTM_RSV 0x10
- #define PM8XXX_ADC_AMUX_MPP_SEL 2
- #define PM8XXX_ADC_AMUX_SEL 4
- #define PM8XXX_ADC_RSV_IP_SEL 4
- #define PM8XXX_ADC_BTM_CHANNEL_SEL 4
- #define PM8XXX_MAX_CHANNEL_PROPERTIES 2
- #define PM8XXX_ADC_IRQ_0 0
- #define PM8XXX_ADC_IRQ_1 1
- #define PM8XXX_ADC_IRQ_2 2
- #define PM8XXX_ADC_BTM_INTERVAL_SEL_MASK 0xF
- #define PM8XXX_ADC_BTM_INTERVAL_SEL_SHIFT 2
- #define PM8XXX_ADC_BTM_DECIMATION_SEL 5
- #define PM8XXX_ADC_MUL 10
- #define PM8XXX_ADC_CONV_TIME_MIN 2000
- #define PM8XXX_ADC_CONV_TIME_MAX 2100
- #define PM8XXX_ADC_MPP_SETTLE_TIME_MIN 200
- #define PM8XXX_ADC_MPP_SETTLE_TIME_MAX 200
- #define PM8XXX_ADC_PA_THERM_VREG_UV_MIN 1800000
- #define PM8XXX_ADC_PA_THERM_VREG_UV_MAX 1800000
- #define PM8XXX_ADC_PA_THERM_VREG_UA_LOAD 100000
- #define PM8XXX_ADC_HWMON_NAME_LENGTH 32
- #define PM8XXX_ADC_BTM_INTERVAL_MAX 0x14
- #define PM8XXX_ADC_COMPLETION_TIMEOUT (2 * HZ)
- struct pm8xxx_adc {
- struct device *dev;
- struct pm8xxx_adc_properties *adc_prop;
- int adc_irq;
- struct mutex adc_lock;
- struct mutex mpp_adc_lock;
- spinlock_t btm_lock;
- uint32_t adc_num_board_channel;
- struct completion adc_rslt_completion;
- struct pm8xxx_adc_amux *adc_channel;
- int btm_warm_irq;
- int btm_cool_irq;
- struct dentry *dent;
- struct work_struct warm_work;
- struct work_struct cool_work;
- uint32_t mpp_base;
- struct device *hwmon;
- struct msm_xo_voter *adc_voter;
- int msm_suspend_check;
- struct pm8xxx_adc_amux_properties *conv;
- struct pm8xxx_adc_arb_btm_param batt;
- struct sensor_device_attribute sens_attr[0];
- };
- struct pm8xxx_adc_amux_properties {
- uint32_t amux_channel;
- uint32_t decimation;
- uint32_t amux_ip_rsv;
- uint32_t amux_mpp_channel;
- struct pm8xxx_adc_chan_properties chan_prop[0];
- };
- static const struct pm8xxx_adc_scaling_ratio pm8xxx_amux_scaling_ratio[] = {
- {1, 1},
- {1, 3},
- {1, 4},
- {1, 6}
- };
- static struct pm8xxx_adc *pmic_adc;
- static struct regulator *pa_therm;
- static struct pm8xxx_adc_scale_fn adc_scale_fn[] = {
- [ADC_SCALE_DEFAULT] = {pm8xxx_adc_scale_default},
- [ADC_SCALE_BATT_THERM] = {pm8xxx_adc_scale_batt_therm},
- [ADC_SCALE_PA_THERM] = {pm8xxx_adc_scale_pa_therm},
- [ADC_SCALE_PMIC_THERM] = {pm8xxx_adc_scale_pmic_therm},
- [ADC_SCALE_XOTHERM] = {pm8xxx_adc_tdkntcg_therm},
- };
- /* 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 */
- static struct pm8xxx_mpp_config_data pm8xxx_adc_mpp_config = {
- .type = PM8XXX_MPP_TYPE_A_INPUT,
- /* AMUX6 is dedicated to be used for apps processor */
- .level = PM8XXX_MPP_AIN_AMUX_CH6,
- .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
- };
- /* MPP Configuration for default settings */
- static struct pm8xxx_mpp_config_data pm8xxx_adc_mpp_unconfig = {
- .type = PM8XXX_MPP_TYPE_SINK,
- .level = PM8XXX_MPP_AIN_AMUX_CH5,
- .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
- };
- static bool pm8xxx_adc_calib_first_adc;
- static bool pm8xxx_adc_initialized, pm8xxx_adc_calib_device_init;
- static int32_t pm8xxx_adc_check_channel_valid(uint32_t channel)
- {
- if (channel < CHANNEL_VCOIN ||
- (channel > CHANNEL_MUXOFF && channel < ADC_MPP_1_ATEST_8) ||
- (channel > ADC_MPP_1_ATEST_7 && channel < ADC_MPP_2_ATEST_8)
- || (channel >= ADC_CHANNEL_MAX_NUM))
- return -EBADF;
- else
- return 0;
- }
- static int32_t pm8xxx_adc_arb_cntrl(uint32_t arb_cntrl,
- uint32_t channel)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int i, rc;
- u8 data_arb_cntrl = 0;
- if (arb_cntrl) {
- if (adc_pmic->msm_suspend_check)
- pr_err("PM8xxx ADC request made after suspend_noirq "
- "with channel: %d\n", channel);
- data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB;
- }
- /* Write twice to the CNTRL register for the arbiter settings
- to take into effect */
- for (i = 0; i < 2; i++) {
- rc = pm8xxx_writeb(adc_pmic->dev->parent,
- PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
- if (rc < 0) {
- pr_err("PM8xxx arb cntrl write failed with %d\n", rc);
- return rc;
- }
- }
- if (arb_cntrl) {
- data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_REQ;
- INIT_COMPLETION(adc_pmic->adc_rslt_completion);
- rc = pm8xxx_writeb(adc_pmic->dev->parent,
- PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
- }
- return 0;
- }
- static int32_t pm8xxx_adc_patherm_power(bool on)
- {
- int rc = 0;
- if (!pa_therm) {
- pr_err("pm8xxx adc pa_therm not valid\n");
- return -EINVAL;
- }
- if (on) {
- rc = regulator_set_voltage(pa_therm,
- PM8XXX_ADC_PA_THERM_VREG_UV_MIN,
- PM8XXX_ADC_PA_THERM_VREG_UV_MAX);
- if (rc < 0) {
- pr_err("failed to set the voltage for "
- "pa_therm with error %d\n", rc);
- return rc;
- }
- rc = regulator_set_optimum_mode(pa_therm,
- PM8XXX_ADC_PA_THERM_VREG_UA_LOAD);
- if (rc < 0) {
- pr_err("failed to set optimum mode for "
- "pa_therm with error %d\n", rc);
- return rc;
- }
- rc = regulator_enable(pa_therm);
- if (rc < 0) {
- pr_err("failed to enable pa_therm vreg "
- "with error %d\n", rc);
- return rc;
- }
- } else {
- rc = regulator_disable(pa_therm);
- if (rc < 0) {
- pr_err("failed to disable pa_therm vreg "
- "with error %d\n", rc);
- return rc;
- }
- }
- return rc;
- }
- static int32_t pm8xxx_adc_xo_vote(bool on)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- if (on)
- msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
- else
- msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
- return 0;
- }
- static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
- bool power_cntrl)
- {
- int rc = 0;
- switch (channel) {
- case ADC_MPP_1_AMUX8:
- rc = pm8xxx_adc_patherm_power(power_cntrl);
- break;
- case CHANNEL_DIE_TEMP:
- case CHANNEL_MUXOFF:
- rc = pm8xxx_adc_xo_vote(power_cntrl);
- break;
- default:
- break;
- }
- return rc;
- }
- static uint32_t pm8xxx_adc_read_reg(uint32_t reg, u8 *data)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int rc;
- rc = pm8xxx_readb(adc_pmic->dev->parent, reg, data);
- if (rc < 0) {
- pr_err("PM8xxx adc read reg %d failed with %d\n", reg, rc);
- return rc;
- }
- return 0;
- }
- static uint32_t pm8xxx_adc_write_reg(uint32_t reg, u8 data)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int rc;
- rc = pm8xxx_writeb(adc_pmic->dev->parent, reg, data);
- if (rc < 0) {
- pr_err("PM8xxx adc write reg %d failed with %d\n", reg, rc);
- return rc;
- }
- return 0;
- }
- static int32_t pm8xxx_adc_configure(
- struct pm8xxx_adc_amux_properties *chan_prop)
- {
- u8 data_amux_chan = 0, data_arb_rsv = 0, data_dig_param = 0;
- int rc;
- data_amux_chan |= chan_prop->amux_channel << PM8XXX_ADC_AMUX_SEL;
- if (chan_prop->amux_mpp_channel)
- data_amux_chan |= chan_prop->amux_mpp_channel <<
- PM8XXX_ADC_AMUX_MPP_SEL;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_AMUX_CNTRL,
- data_amux_chan);
- if (rc < 0)
- return rc;
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_RSV, &data_arb_rsv);
- if (rc < 0)
- return rc;
- data_arb_rsv &= (PM8XXX_ADC_ARB_USRP_RSV_RST |
- PM8XXX_ADC_ARB_USRP_RSV_DTEST0 |
- PM8XXX_ADC_ARB_USRP_RSV_DTEST1 |
- PM8XXX_ADC_ARB_USRP_RSV_OP);
- data_arb_rsv |= (chan_prop->amux_ip_rsv << PM8XXX_ADC_RSV_IP_SEL |
- PM8XXX_ADC_ARB_USRP_RSV_TRM);
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_RSV, data_arb_rsv);
- if (rc < 0)
- return rc;
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_DIG_PARAM,
- &data_dig_param);
- if (rc < 0)
- return rc;
- /* Default 2.4Mhz clock rate */
- /* Client chooses the decimation */
- switch (chan_prop->decimation) {
- case ADC_DECIMATION_TYPE1:
- data_dig_param |= PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
- break;
- case ADC_DECIMATION_TYPE2:
- data_dig_param |= (PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0
- | PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1);
- break;
- default:
- data_dig_param |= PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
- break;
- }
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_DIG_PARAM,
- PM8XXX_ADC_ARB_ANA_DIG);
- if (rc < 0)
- return rc;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_ANA_PARAM,
- PM8XXX_ADC_ARB_ANA_DIG);
- if (rc < 0)
- return rc;
- rc = pm8xxx_adc_arb_cntrl(1, data_amux_chan);
- if (rc < 0) {
- pr_err("Configuring ADC Arbiter"
- "enable failed with %d\n", rc);
- return rc;
- }
- return 0;
- }
- static uint32_t pm8xxx_adc_read_adc_code(int32_t *data)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- uint8_t rslt_lsb, rslt_msb;
- int32_t rc, max_ideal_adc_code = 1 << adc_pmic->adc_prop->bitresolution;
- rc = pm8xxx_readb(adc_pmic->dev->parent,
- PM8XXX_ADC_ARB_USRP_DATA0, &rslt_lsb);
- if (rc < 0) {
- pr_err("PM8xxx adc result read failed with %d\n", rc);
- return rc;
- }
- rc = pm8xxx_readb(adc_pmic->dev->parent,
- PM8XXX_ADC_ARB_USRP_DATA1, &rslt_msb);
- if (rc < 0) {
- pr_err("PM8xxx adc result read failed with %d\n", rc);
- return rc;
- }
- *data = (rslt_msb << 8) | rslt_lsb;
- /* Use the midpoint to determine underflow or overflow */
- if (*data > max_ideal_adc_code + (max_ideal_adc_code >> 1))
- *data |= ((1 << (8 * sizeof(*data) -
- adc_pmic->adc_prop->bitresolution)) - 1) <<
- adc_pmic->adc_prop->bitresolution;
- /* Default value for switching off the arbiter after reading
- the ADC value. Bit 0 set to 0. */
- rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
- if (rc < 0) {
- pr_err("%s: Configuring ADC Arbiter disable"
- "failed\n", __func__);
- return rc;
- }
- return 0;
- }
- static void pm8xxx_adc_btm_warm_scheduler_fn(struct work_struct *work)
- {
- struct pm8xxx_adc *adc_pmic = container_of(work, struct pm8xxx_adc,
- warm_work);
- unsigned long flags = 0;
- bool warm_status;
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- warm_status = irq_read_line(adc_pmic->btm_warm_irq);
- if (adc_pmic->batt.btm_warm_fn != NULL)
- adc_pmic->batt.btm_warm_fn(warm_status);
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- }
- static void pm8xxx_adc_btm_cool_scheduler_fn(struct work_struct *work)
- {
- struct pm8xxx_adc *adc_pmic = container_of(work, struct pm8xxx_adc,
- cool_work);
- unsigned long flags = 0;
- bool cool_status;
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- cool_status = irq_read_line(adc_pmic->btm_cool_irq);
- if (adc_pmic->batt.btm_cool_fn != NULL)
- adc_pmic->batt.btm_cool_fn(cool_status);
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- }
- void trigger_completion(struct work_struct *work)
- {
- struct pm8xxx_adc *adc_8xxx = pmic_adc;
- complete(&adc_8xxx->adc_rslt_completion);
- }
- DECLARE_WORK(trigger_completion_work, trigger_completion);
- static irqreturn_t pm8xxx_adc_isr(int irq, void *dev_id)
- {
- if (pm8xxx_adc_calib_first_adc)
- return IRQ_HANDLED;
- schedule_work(&trigger_completion_work);
- return IRQ_HANDLED;
- }
- static irqreturn_t pm8xxx_btm_warm_isr(int irq, void *dev_id)
- {
- struct pm8xxx_adc *btm_8xxx = dev_id;
- schedule_work(&btm_8xxx->warm_work);
- return IRQ_HANDLED;
- }
- static irqreturn_t pm8xxx_btm_cool_isr(int irq, void *dev_id)
- {
- struct pm8xxx_adc *btm_8xxx = dev_id;
- schedule_work(&btm_8xxx->cool_work);
- return IRQ_HANDLED;
- }
- static uint32_t pm8xxx_adc_calib_device(void)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- struct pm8xxx_adc_amux_properties conv;
- int rc, calib_read_1, calib_read_2;
- u8 data_arb_usrp_cntrl1 = 0;
- conv.amux_channel = CHANNEL_125V;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV1;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8xxx_adc_calib_first_adc = true;
- rc = pm8xxx_adc_configure(&conv);
- if (rc) {
- pr_err("pm8xxx_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
- while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
- PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
- PM8XXX_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
- rc = pm8xxx_adc_read_adc_code(&calib_read_1);
- if (rc) {
- pr_err("pm8xxx_adc read adc failed with %d\n", rc);
- pm8xxx_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8xxx_adc_calib_first_adc = false;
- conv.amux_channel = CHANNEL_625MV;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV1;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8xxx_adc_calib_first_adc = true;
- rc = pm8xxx_adc_configure(&conv);
- if (rc) {
- pr_err("pm8xxx_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
- while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
- PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
- PM8XXX_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
- rc = pm8xxx_adc_read_adc_code(&calib_read_2);
- if (rc) {
- pr_err("pm8xxx_adc read adc failed with %d\n", rc);
- pm8xxx_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8xxx_adc_calib_first_adc = false;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dy =
- (calib_read_1 - calib_read_2);
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dx
- = PM8XXX_CHANNEL_ADC_625_UV;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_vref =
- calib_read_1;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd =
- calib_read_2;
- rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
- if (rc < 0) {
- pr_err("%s: Configuring ADC Arbiter disable"
- "failed\n", __func__);
- return rc;
- }
- /* Ratiometric Calibration */
- conv.amux_channel = CHANNEL_MUXOFF;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV5;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8xxx_adc_calib_first_adc = true;
- rc = pm8xxx_adc_configure(&conv);
- if (rc) {
- pr_err("pm8xxx_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
- while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
- PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
- PM8XXX_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
- rc = pm8xxx_adc_read_adc_code(&calib_read_1);
- if (rc) {
- pr_err("pm8xxx_adc read adc failed with %d\n", rc);
- pm8xxx_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8xxx_adc_calib_first_adc = false;
- conv.amux_channel = CHANNEL_MUXOFF;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV4;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8xxx_adc_calib_first_adc = true;
- rc = pm8xxx_adc_configure(&conv);
- if (rc) {
- pr_err("pm8xxx_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
- while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
- PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
- PM8XXX_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
- rc = pm8xxx_adc_read_adc_code(&calib_read_2);
- if (rc) {
- pr_err("pm8xxx_adc read adc failed with %d\n", rc);
- pm8xxx_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8xxx_adc_calib_first_adc = false;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dy =
- (calib_read_1 - calib_read_2);
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dx =
- adc_pmic->adc_prop->adc_vdd_reference;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_vref =
- calib_read_1;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd =
- calib_read_2;
- calib_fail:
- rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
- if (rc < 0) {
- pr_err("%s: Configuring ADC Arbiter disable"
- "failed\n", __func__);
- }
- return rc;
- }
- uint32_t pm8xxx_adc_read(enum pm8xxx_adc_channels channel,
- struct pm8xxx_adc_chan_result *result)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int i = 0, rc = 0, rc_fail, amux_prescaling, scale_type;
- enum pm8xxx_adc_premux_mpp_scale_type mpp_scale;
- if (!pm8xxx_adc_initialized)
- return -ENODEV;
- if (!pm8xxx_adc_calib_device_init) {
- if (pm8xxx_adc_calib_device() == 0)
- pm8xxx_adc_calib_device_init = true;
- }
- mutex_lock(&adc_pmic->adc_lock);
- for (i = 0; i < adc_pmic->adc_num_board_channel; i++) {
- if (channel == adc_pmic->adc_channel[i].channel_name)
- break;
- }
- if (i == adc_pmic->adc_num_board_channel ||
- (pm8xxx_adc_check_channel_valid(channel) != 0)) {
- rc = -EBADF;
- goto fail_unlock;
- }
- if (channel < PM8XXX_CHANNEL_MPP_SCALE1_IDX) {
- mpp_scale = PREMUX_MPP_SCALE_0;
- adc_pmic->conv->amux_channel = channel;
- } else if (channel >= PM8XXX_CHANNEL_MPP_SCALE1_IDX &&
- channel < PM8XXX_CHANNEL_MPP_SCALE3_IDX) {
- mpp_scale = PREMUX_MPP_SCALE_1;
- adc_pmic->conv->amux_channel = channel %
- PM8XXX_CHANNEL_MPP_SCALE1_IDX;
- } else {
- mpp_scale = PREMUX_MPP_SCALE_1_DIV3;
- adc_pmic->conv->amux_channel = channel %
- PM8XXX_CHANNEL_MPP_SCALE3_IDX;
- }
- adc_pmic->conv->amux_mpp_channel = mpp_scale;
- adc_pmic->conv->amux_ip_rsv = adc_pmic->adc_channel[i].adc_rsv;
- adc_pmic->conv->decimation = adc_pmic->adc_channel[i].adc_decimation;
- amux_prescaling = adc_pmic->adc_channel[i].chan_path_prescaling;
- adc_pmic->conv->chan_prop->offset_gain_numerator =
- pm8xxx_amux_scaling_ratio[amux_prescaling].num;
- adc_pmic->conv->chan_prop->offset_gain_denominator =
- pm8xxx_amux_scaling_ratio[amux_prescaling].den;
- rc = pm8xxx_adc_channel_power_enable(channel, true);
- if (rc) {
- rc = -EINVAL;
- goto fail_unlock;
- }
- rc = pm8xxx_adc_configure(adc_pmic->conv);
- if (rc) {
- rc = -EINVAL;
- goto fail;
- }
- rc = wait_for_completion_timeout(&adc_pmic->adc_rslt_completion,
- PM8XXX_ADC_COMPLETION_TIMEOUT);
- if (!rc) {
- u8 data_arb_usrp_cntrl1 = 0;
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- goto fail;
- if (data_arb_usrp_cntrl1 == (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
- PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB))
- pr_debug("End of conversion status set\n");
- else {
- pr_err("EOC interrupt not received\n");
- rc = -EINVAL;
- goto fail;
- }
- }
- rc = pm8xxx_adc_read_adc_code(&result->adc_code);
- if (rc) {
- rc = -EINVAL;
- goto fail;
- }
- scale_type = adc_pmic->adc_channel[i].adc_scale_fn;
- if (scale_type >= ADC_SCALE_NONE) {
- rc = -EBADF;
- goto fail;
- }
- adc_scale_fn[scale_type].chan(result->adc_code,
- adc_pmic->adc_prop, adc_pmic->conv->chan_prop, result);
- rc = pm8xxx_adc_channel_power_enable(channel, false);
- if (rc) {
- rc = -EINVAL;
- goto fail_unlock;
- }
- mutex_unlock(&adc_pmic->adc_lock);
- return 0;
- fail:
- rc_fail = pm8xxx_adc_channel_power_enable(channel, false);
- if (rc_fail)
- pr_err("pm8xxx adc power disable failed\n");
- fail_unlock:
- mutex_unlock(&adc_pmic->adc_lock);
- pr_err("pm8xxx adc error with %d\n", rc);
- return rc;
- }
- EXPORT_SYMBOL_GPL(pm8xxx_adc_read);
- uint32_t pm8xxx_adc_mpp_config_read(uint32_t mpp_num,
- enum pm8xxx_adc_channels channel,
- struct pm8xxx_adc_chan_result *result)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int rc = 0;
- if (!pm8xxx_adc_initialized)
- return -ENODEV;
- if (!adc_pmic->mpp_base) {
- rc = -EINVAL;
- pr_info("PM8xxx MPP base invalid with error %d\n", rc);
- return rc;
- }
- if (mpp_num == PM8XXX_AMUX_MPP_8) {
- rc = -EINVAL;
- pr_info("PM8xxx MPP8 is already configured "
- "to AMUX8. Use pm8xxx_adc_read() instead.\n");
- return rc;
- }
- mutex_lock(&adc_pmic->mpp_adc_lock);
- rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
- &pm8xxx_adc_mpp_config);
- if (rc < 0) {
- pr_err("pm8xxx adc mpp config error with %d\n", rc);
- goto fail;
- }
- usleep_range(PM8XXX_ADC_MPP_SETTLE_TIME_MIN,
- PM8XXX_ADC_MPP_SETTLE_TIME_MAX);
- rc = pm8xxx_adc_read(channel, result);
- if (rc < 0)
- pr_err("pm8xxx adc read error with %d\n", rc);
- rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
- &pm8xxx_adc_mpp_unconfig);
- if (rc < 0)
- pr_err("pm8xxx adc mpp config error with %d\n", rc);
- fail:
- mutex_unlock(&adc_pmic->mpp_adc_lock);
- return rc;
- }
- EXPORT_SYMBOL_GPL(pm8xxx_adc_mpp_config_read);
- uint32_t pm8xxx_adc_btm_configure(struct pm8xxx_adc_arb_btm_param *btm_param)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- u8 data_btm_cool_thr0, data_btm_cool_thr1;
- u8 data_btm_warm_thr0, data_btm_warm_thr1;
- u8 arb_btm_cntrl1;
- unsigned long flags = 0;
- int rc;
- if (adc_pmic == NULL) {
- pr_err("PMIC ADC not valid\n");
- return -EINVAL;
- }
- if ((btm_param->btm_cool_fn == NULL) &&
- (btm_param->btm_warm_fn == NULL)) {
- pr_err("No BTM warm/cool notification??\n");
- return -EINVAL;
- }
- rc = pm8xxx_adc_batt_scaler(btm_param, adc_pmic->adc_prop,
- adc_pmic->conv->chan_prop);
- if (rc < 0) {
- pr_err("Failed to lookup the BTM thresholds\n");
- return rc;
- }
- if (btm_param->interval > PM8XXX_ADC_BTM_INTERVAL_MAX) {
- pr_info("Bug in PMIC BTM interval time and cannot set"
- " a value greater than 0x14 %x\n", btm_param->interval);
- btm_param->interval = PM8XXX_ADC_BTM_INTERVAL_MAX;
- }
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- data_btm_cool_thr0 = ((btm_param->low_thr_voltage << 24) >> 24);
- data_btm_cool_thr1 = ((btm_param->low_thr_voltage << 16) >> 24);
- data_btm_warm_thr0 = ((btm_param->high_thr_voltage << 24) >> 24);
- data_btm_warm_thr1 = ((btm_param->high_thr_voltage << 16) >> 24);
- if (btm_param->btm_cool_fn != NULL) {
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_COOL_THR0,
- data_btm_cool_thr0);
- if (rc < 0)
- goto write_err;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_COOL_THR1,
- data_btm_cool_thr1);
- if (rc < 0)
- goto write_err;
- adc_pmic->batt.btm_cool_fn = btm_param->btm_cool_fn;
- }
- if (btm_param->btm_warm_fn != NULL) {
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_WARM_THR0,
- data_btm_warm_thr0);
- if (rc < 0)
- goto write_err;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_WARM_THR1,
- data_btm_warm_thr1);
- if (rc < 0)
- goto write_err;
- adc_pmic->batt.btm_warm_fn = btm_param->btm_warm_fn;
- }
- rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, &arb_btm_cntrl1);
- if (rc < 0)
- goto bail_out;
- btm_param->interval &= PM8XXX_ADC_BTM_INTERVAL_SEL_MASK;
- arb_btm_cntrl1 |=
- btm_param->interval << PM8XXX_ADC_BTM_INTERVAL_SEL_SHIFT;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, arb_btm_cntrl1);
- if (rc < 0)
- goto write_err;
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
- bail_out:
- write_err:
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- pr_debug("%s: with error code %d\n", __func__, rc);
- return rc;
- }
- EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_configure);
- static uint32_t pm8xxx_adc_btm_read(uint32_t channel)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int rc, i;
- u8 arb_btm_dig_param, arb_btm_ana_param, arb_btm_rsv;
- u8 arb_btm_amux_cntrl, data_arb_btm_cntrl = 0;
- unsigned long flags;
- arb_btm_amux_cntrl = channel << PM8XXX_ADC_BTM_CHANNEL_SEL;
- arb_btm_rsv = adc_pmic->adc_channel[channel].adc_rsv;
- arb_btm_dig_param = arb_btm_ana_param = PM8XXX_ADC_ARB_ANA_DIG;
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_AMUX_CNTRL,
- arb_btm_amux_cntrl);
- if (rc < 0)
- goto write_err;
- arb_btm_rsv = PM8XXX_ADC_BTM_RSV;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_RSV, arb_btm_rsv);
- if (rc < 0)
- goto write_err;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_DIG_PARAM,
- arb_btm_dig_param);
- if (rc < 0)
- goto write_err;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_ANA_PARAM,
- arb_btm_ana_param);
- if (rc < 0)
- goto write_err;
- data_arb_btm_cntrl |= PM8XXX_ADC_ARB_BTM_CNTRL1_EN_BTM;
- for (i = 0; i < 2; i++) {
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
- data_arb_btm_cntrl);
- if (rc < 0)
- goto write_err;
- }
- data_arb_btm_cntrl |= PM8XXX_ADC_ARB_BTM_CNTRL1_REQ
- | PM8XXX_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE;
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
- data_arb_btm_cntrl);
- if (rc < 0)
- goto write_err;
- if (pmic_adc->batt.btm_warm_fn != NULL)
- enable_irq(adc_pmic->btm_warm_irq);
- if (pmic_adc->batt.btm_cool_fn != NULL)
- enable_irq(adc_pmic->btm_cool_irq);
- write_err:
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
- }
- uint32_t pm8xxx_adc_btm_start(void)
- {
- return pm8xxx_adc_btm_read(CHANNEL_BATT_THERM);
- }
- EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_start);
- uint32_t pm8xxx_adc_btm_end(void)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int i, rc;
- u8 data_arb_btm_cntrl = 0;
- unsigned long flags;
- disable_irq_nosync(adc_pmic->btm_warm_irq);
- disable_irq_nosync(adc_pmic->btm_cool_irq);
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- /* Write twice to the CNTRL register for the arbiter settings
- to take into effect */
- for (i = 0; i < 2; i++) {
- rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
- data_arb_btm_cntrl);
- if (rc < 0) {
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
- }
- }
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
- }
- EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_end);
- static ssize_t pm8xxx_adc_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct pm8xxx_adc_chan_result result;
- int rc = -1;
- rc = pm8xxx_adc_read(attr->index, &result);
- if (rc)
- return 0;
- return snprintf(buf, PM8XXX_ADC_HWMON_NAME_LENGTH,
- "Result:%lld Raw:%d\n", result.physical, result.adc_code);
- }
- static int get_adc(void *data, u64 *val)
- {
- struct pm8xxx_adc_chan_result result;
- int i = (int)data;
- int rc;
- rc = pm8xxx_adc_read(i, &result);
- if (!rc)
- pr_info("ADC value raw:%x physical:%lld\n",
- result.adc_code, result.physical);
- *val = result.physical;
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_adc, NULL, "%lld\n");
- #ifdef CONFIG_DEBUG_FS
- static void create_debugfs_entries(void)
- {
- int i = 0;
- pmic_adc->dent = debugfs_create_dir("pm8xxx_adc", NULL);
- if (IS_ERR(pmic_adc->dent)) {
- pr_err("pmic adc debugfs dir not created\n");
- return;
- }
- for (i = 0; i < pmic_adc->adc_num_board_channel; i++)
- debugfs_create_file(pmic_adc->adc_channel[i].name,
- 0644, pmic_adc->dent,
- (void *)pmic_adc->adc_channel[i].channel_name,
- ®_fops);
- }
- #else
- static inline void create_debugfs_entries(void)
- {
- }
- #endif
- static struct sensor_device_attribute pm8xxx_adc_attr =
- SENSOR_ATTR(NULL, S_IRUGO, pm8xxx_adc_show, NULL, 0);
- static int32_t pm8xxx_adc_init_hwmon(struct platform_device *pdev)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int rc = 0, i, channel;
- for (i = 0; i < pmic_adc->adc_num_board_channel; i++) {
- channel = adc_pmic->adc_channel[i].channel_name;
- if (pm8xxx_adc_check_channel_valid(channel)) {
- pr_err("Invalid ADC init HWMON channel: %d\n", channel);
- continue;
- }
- pm8xxx_adc_attr.index = adc_pmic->adc_channel[i].channel_name;
- pm8xxx_adc_attr.dev_attr.attr.name =
- adc_pmic->adc_channel[i].name;
- memcpy(&adc_pmic->sens_attr[i], &pm8xxx_adc_attr,
- sizeof(pm8xxx_adc_attr));
- sysfs_attr_init(&adc_pmic->sens_attr[i].dev_attr.attr);
- rc = device_create_file(&pdev->dev,
- &adc_pmic->sens_attr[i].dev_attr);
- if (rc) {
- dev_err(&pdev->dev, "device_create_file failed for "
- "dev %s\n",
- adc_pmic->adc_channel[i].name);
- goto hwmon_err_sens;
- }
- }
- return 0;
- hwmon_err_sens:
- pr_info("Init HWMON failed for pm8xxx_adc with %d\n", rc);
- return rc;
- }
- #ifdef CONFIG_PM
- static int pm8xxx_adc_suspend_noirq(struct device *dev)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- adc_pmic->msm_suspend_check = 1;
- return 0;
- }
- static int pm8xxx_adc_resume_noirq(struct device *dev)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- adc_pmic->msm_suspend_check = 0;
- return 0;
- }
- static const struct dev_pm_ops pm8xxx_adc_dev_pm_ops = {
- .suspend_noirq = pm8xxx_adc_suspend_noirq,
- .resume_noirq = pm8xxx_adc_resume_noirq,
- };
- #define PM8XXX_ADC_DEV_PM_OPS (&pm8xxx_adc_dev_pm_ops)
- #else
- #define PM8XXX_ADC_DEV_PM_OPS NULL
- #endif
- static int __devexit pm8xxx_adc_teardown(struct platform_device *pdev)
- {
- struct pm8xxx_adc *adc_pmic = pmic_adc;
- int i;
- msm_xo_put(adc_pmic->adc_voter);
- platform_set_drvdata(pdev, NULL);
- pmic_adc = NULL;
- if (!pa_therm) {
- regulator_put(pa_therm);
- pa_therm = NULL;
- }
- for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
- device_remove_file(adc_pmic->dev,
- &adc_pmic->sens_attr[i].dev_attr);
- pm8xxx_adc_initialized = false;
- return 0;
- }
- static int __devinit pm8xxx_adc_probe(struct platform_device *pdev)
- {
- const struct pm8xxx_adc_platform_data *pdata = pdev->dev.platform_data;
- struct pm8xxx_adc *adc_pmic;
- struct pm8xxx_adc_amux_properties *adc_amux_prop;
- int rc = 0;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data?\n");
- return -EINVAL;
- }
- adc_pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8xxx_adc) +
- (sizeof(struct sensor_device_attribute) *
- pdata->adc_num_board_channel), GFP_KERNEL);
- if (!adc_pmic) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
- adc_amux_prop = devm_kzalloc(&pdev->dev,
- sizeof(struct pm8xxx_adc_amux_properties) +
- sizeof(struct pm8xxx_adc_chan_properties)
- , GFP_KERNEL);
- if (!adc_amux_prop) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
- adc_pmic->dev = &pdev->dev;
- adc_pmic->adc_prop = pdata->adc_prop;
- adc_pmic->conv = adc_amux_prop;
- init_completion(&adc_pmic->adc_rslt_completion);
- adc_pmic->adc_channel = pdata->adc_channel;
- adc_pmic->adc_num_board_channel = pdata->adc_num_board_channel;
- adc_pmic->mpp_base = pdata->adc_mpp_base;
- mutex_init(&adc_pmic->adc_lock);
- mutex_init(&adc_pmic->mpp_adc_lock);
- spin_lock_init(&adc_pmic->btm_lock);
- adc_pmic->adc_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_0);
- if (adc_pmic->adc_irq < 0)
- return adc_pmic->adc_irq;
- rc = devm_request_irq(&pdev->dev, adc_pmic->adc_irq,
- pm8xxx_adc_isr,
- IRQF_TRIGGER_RISING, "pm8xxx_adc_interrupt", adc_pmic);
- if (rc) {
- dev_err(&pdev->dev, "failed to request adc irq "
- "with error %d\n", rc);
- } else {
- enable_irq_wake(adc_pmic->adc_irq);
- }
- adc_pmic->btm_warm_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_1);
- if (adc_pmic->btm_warm_irq < 0)
- return adc_pmic->btm_warm_irq;
- rc = devm_request_irq(&pdev->dev, adc_pmic->btm_warm_irq,
- pm8xxx_btm_warm_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "pm8xxx_btm_warm_interrupt", adc_pmic);
- if (rc) {
- pr_err("btm warm irq failed %d with interrupt number %d\n",
- rc, adc_pmic->btm_warm_irq);
- dev_err(&pdev->dev, "failed to request btm irq\n");
- }
- disable_irq_nosync(adc_pmic->btm_warm_irq);
- adc_pmic->btm_cool_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_2);
- if (adc_pmic->btm_cool_irq < 0)
- return adc_pmic->btm_cool_irq;
- rc = devm_request_irq(&pdev->dev, adc_pmic->btm_cool_irq,
- pm8xxx_btm_cool_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "pm8xxx_btm_cool_interrupt", adc_pmic);
- if (rc) {
- pr_err("btm cool irq failed with return %d and number %d\n",
- rc, adc_pmic->btm_cool_irq);
- dev_err(&pdev->dev, "failed to request btm irq\n");
- }
- disable_irq_nosync(adc_pmic->btm_cool_irq);
- platform_set_drvdata(pdev, adc_pmic);
- adc_pmic->msm_suspend_check = 0;
- pmic_adc = adc_pmic;
- INIT_WORK(&adc_pmic->warm_work, pm8xxx_adc_btm_warm_scheduler_fn);
- INIT_WORK(&adc_pmic->cool_work, pm8xxx_adc_btm_cool_scheduler_fn);
- create_debugfs_entries();
- pm8xxx_adc_calib_first_adc = false;
- pm8xxx_adc_calib_device_init = false;
- pm8xxx_adc_initialized = true;
- rc = pm8xxx_adc_init_hwmon(pdev);
- if (rc) {
- pr_err("pm8xxx adc init hwmon failed with %d\n", rc);
- dev_err(&pdev->dev, "failed to initialize pm8xxx hwmon adc\n");
- }
- adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
- if (adc_pmic->adc_voter == NULL) {
- adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D0, "pmic_xoadc");
- if (IS_ERR(adc_pmic->adc_voter)) {
- dev_err(&pdev->dev, "Failed to get XO vote\n");
- return PTR_ERR(adc_pmic->adc_voter);
- }
- }
- pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
- if (IS_ERR(pa_therm)) {
- rc = PTR_ERR(pa_therm);
- pr_err("failed to request pa_therm vreg with error %d\n", rc);
- pa_therm = NULL;
- }
- return 0;
- }
- static struct platform_driver pm8xxx_adc_driver = {
- .probe = pm8xxx_adc_probe,
- .remove = __devexit_p(pm8xxx_adc_teardown),
- .driver = {
- .name = PM8XXX_ADC_DEV_NAME,
- .owner = THIS_MODULE,
- .pm = PM8XXX_ADC_DEV_PM_OPS,
- },
- };
- static int __init pm8xxx_adc_init(void)
- {
- return platform_driver_register(&pm8xxx_adc_driver);
- }
- module_init(pm8xxx_adc_init);
- static void __exit pm8xxx_adc_exit(void)
- {
- platform_driver_unregister(&pm8xxx_adc_driver);
- }
- module_exit(pm8xxx_adc_exit);
- MODULE_ALIAS("platform:" PM8XXX_ADC_DEV_NAME);
- MODULE_DESCRIPTION("PMIC8921/8018 ADC driver");
- MODULE_LICENSE("GPL v2");
|