diff options
Diffstat (limited to 'drivers/staging/intel_sst/intelmid_adc_control.h')
-rw-r--r-- | drivers/staging/intel_sst/intelmid_adc_control.h | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/drivers/staging/intel_sst/intelmid_adc_control.h b/drivers/staging/intel_sst/intelmid_adc_control.h new file mode 100644 index 0000000..65d5c39 --- /dev/null +++ b/drivers/staging/intel_sst/intelmid_adc_control.h @@ -0,0 +1,193 @@ +#ifndef __INTELMID_ADC_CONTROL_H__ +#define __INTELMID_ADC_CONTROL_H_ +/* + * intelmid_adc_control.h - Intel SST Driver for audio engine + * + * Copyright (C) 2008-10 Intel Corporation + * Authors: R Durgadadoss <r.durgadoss@intel.com> + * Dharageswari R <dharageswari.r@intel.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Common private ADC declarations for SST + */ + + +#define MSIC_ADC1CNTL1 0x1C0 +#define MSIC_ADC_ENBL 0x10 +#define MSIC_ADC_START 0x08 + +#define MSIC_ADC1CNTL3 0x1C2 +#define MSIC_ADCTHERM_ENBL 0x04 +#define MSIC_ADCRRDATA_ENBL 0x05 + +#define MSIC_STOPBIT_MASK 16 +#define MSIC_ADCTHERM_MASK 4 + +#define ADC_CHANLS_MAX 15 /* Number of ADC channels */ +#define ADC_LOOP_MAX (ADC_CHANLS_MAX - 1) + +/* ADC channel code values */ +#define AUDIO_DETECT_CODE 0x06 + +/* ADC base addresses */ +#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ +#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ + + +/** + * configure_adc - enables/disables the ADC for conversion + * @val: zero: disables the ADC non-zero:enables the ADC + * + * Enable/Disable the ADC depending on the argument + * + * Can sleep + */ +static inline int configure_adc(int val) +{ + int ret; + struct sc_reg_access sc_access = {0,}; + + + sc_access.reg_addr = MSIC_ADC1CNTL1; + ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); + if (ret) + return ret; + + if (val) + /* Enable and start the ADC */ + sc_access.value |= (MSIC_ADC_ENBL | MSIC_ADC_START); + else + /* Just stop the ADC */ + sc_access.value &= (~MSIC_ADC_START); + sc_access.reg_addr = MSIC_ADC1CNTL1; + return sst_sc_reg_access(&sc_access, PMIC_WRITE, 1); +} + +/** + * reset_stopbit - sets the stop bit to 0 on the given channel + * @addr: address of the channel + * + * Can sleep + */ +static inline int reset_stopbit(uint16_t addr) +{ + int ret; + struct sc_reg_access sc_access = {0,}; + sc_access.reg_addr = addr; + ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); + if (ret) + return ret; + /* Set the stop bit to zero */ + sc_access.reg_addr = addr; + sc_access.value = (sc_access.value) & 0xEF; + return sst_sc_reg_access(&sc_access, PMIC_WRITE, 1); +} + +/** + * find_free_channel - finds an empty channel for conversion + * + * If the ADC is not enabled then start using 0th channel + * itself. Otherwise find an empty channel by looking for a + * channel in which the stopbit is set to 1. returns the index + * of the first free channel if succeeds or an error code. + * + * Context: can sleep + * + */ +static inline int find_free_channel(void) +{ + int ret; + int i; + + struct sc_reg_access sc_access = {0,}; + + /* check whether ADC is enabled */ + sc_access.reg_addr = MSIC_ADC1CNTL1; + ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); + if (ret) + return ret; + + if ((sc_access.value & MSIC_ADC_ENBL) == 0) + return 0; + + /* ADC is already enabled; Looking for an empty channel */ + for (i = 0; i < ADC_CHANLS_MAX; i++) { + + sc_access.reg_addr = ADC_CHNL_START_ADDR + i; + ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); + if (ret) + return ret; + + if (sc_access.value & MSIC_STOPBIT_MASK) { + ret = i; + break; + } + } + return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; +} + +/** + * mid_initialize_adc - initializing the ADC + * @dev: our device structure + * + * Initialize the ADC for reading thermistor values. Can sleep. + */ +static inline int mid_initialize_adc(void) +{ + int base_addr, chnl_addr; + int ret; + static int channel_index; + struct sc_reg_access sc_access = {0,}; + + /* Index of the first channel in which the stop bit is set */ + channel_index = find_free_channel(); + if (channel_index < 0) { + pr_err("No free ADC channels"); + return channel_index; + } + + base_addr = ADC_CHNL_START_ADDR + channel_index; + + if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { + /* Reset stop bit for channels other than 0 and 12 */ + ret = reset_stopbit(base_addr); + if (ret) + return ret; + + /* Index of the first free channel */ + base_addr++; + channel_index++; + } + + /* Since this is the last channel, set the stop bit + to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ + sc_access.reg_addr = base_addr; + sc_access.value = AUDIO_DETECT_CODE | 0x10; + ret = sst_sc_reg_access(&sc_access, PMIC_WRITE, 1); + if (ret) { + pr_err("unable to enable ADC"); + return ret; + } + + chnl_addr = ADC_DATA_START_ADDR + 2 * channel_index; + pr_debug("mid_initialize : %x", chnl_addr); + configure_adc(1); + return chnl_addr; +} +#endif + |