#ifndef CS4251_H
#define CS4251_H
/*
 * CS42L51 A/D, D/A Converter handling routines.
 *
 * Copyright 2006 Sony Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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
 *
 */

typedef enum { Off = 0, On = 1 } bool_t;

typedef enum {
	off_mode,		/* hold RESET low until the power supplies are stable */
	standby_mode,	/* set the PDN bit to '1'b */
	normal_mode,	/* normal operation */
} cs4251_device_mode_t;

/* SPI or I2C interface */
#define CS4251_CHIP_ADDR	(0x25 << 2)		/* 10010100b */
#define CS4251_READ_BIT		(0x01)
#define CS4251_WRITE_BIT	(0x00)
#define CS4251_MAP_INCR_BIT	(0x80)

/* SPI frame */
typedef struct cs4251_spi_frame {
	uint8_t		addr;	/* b7-b1: chip addr, b0: read/write indicator */
	uint8_t		map;	/* b7: autoincrement, b6-0: Memory Address Pointer */
	uint8_t		data[0];
} cs4251_spi_frame_t;

#define CS4251_MIN_REG_NO	(0x00)
#define CS4251_MAX_REG_NO	(0x38)

/* register bit definition */
#define CS4251_REG01_ID_MASK		(0xf8)	/* chip ID */
#define 	CS4251_CHIP_ID				(0x1b)	/* 11011b */
#define CS4251_REG01_REV_MASK		(0x07)	/* revision ID */

#define CS4251_REG02_PDN_DACB		(0x40)	/* power down DAC ch-B */
#define CS4251_REG02_PDN_DACA		(0x20)	/* power down DAC ch-A */
#define CS4251_REG02_PDN_DAC_MASK	(CS4251_REG02_PDN_DACB | CS4251_REG02_PDN_DACA)
#define CS4251_REG02_PDN_PGAB		(0x10)	/* power down PGA ch-B */
#define CS4251_REG02_PDN_PGAA		(0x08)	/* power down PGA ch-A */
#define CS4251_REG02_PDN_PGA_MASK	(CS4251_REG02_PDN_PGAB | CS4251_REG02_PDN_PGAA)
#define CS4251_REG02_PDN_ADCB		(0x04)	/* power down ADC ch-B */
#define CS4251_REG02_PDN_ADCA		(0x02)	/* power donw ADC ch-A */
#define CS4251_REG02_PDN_ADC_MASK	(CS4251_REG02_PDN_ADCB | CS4251_REG02_PDN_ADCA)
#define CS4251_REG02_PDN			(0x01)	/* power down CODEC */

#define CS4251_REG03_AUTO			(0x80)	/* auto detect speed mode */
#define CS4251_REG03_SPEED_MASK		(0x60)	/* speed mode */
#define 	CS4251_SPEED_MODE_QSM		(3)		/* quarter speed mode. 4 to 12.5kHz */
#define 	CS4251_SPEED_MODE_HSM		(2)		/* half speed mode. 12.5 to 25kHz */
#define 	CS4251_SPEED_MODE_SSM		(1)		/* single speed mode. 4 to 50kHz */
#define 	CS4251_SPEED_MODE_DSM		(0)		/* double speed mode. 50 to 100kHz */
#define CS4251_REG03_3ST_SP			(0x10)	/* tri-state serial port interface */
#define CS4251_REG03_PDN_MICB		(0x08)	/* power down MIC ch-B */
#define CS4251_REG03_PDN_MICA		(0x04)	/* power down MIC ch-A */
#define CS4251_REG03_PDN_MIC_MASK	(CS4251_REG03_PDN_MICB | CS4251_REG03_PDN_MICA)
#define CS4251_REG03_PDN_MICBIAS	(0x02)	/* power down MIC BIAS */
#define CS4251_REG03_MCLKDIV2		(0x01)	/* MCLK divide by 2 */

#define CS4251_REG04_SDOUT_SDIN		(0x80)	/* SDOUT to SDIN loopback */
#define CS4251_REG04_MASTER_SLAVE	(0x40)	/* master(1) or slave(0) */
#define CS4251_REG04_DAC_DIF_MASK	(0x38)	/* DAC digital interface format */
#define 	CS4251_DAC_DIF_LEFT_24		(0)		/* left justified, up to 24bit */
#define 	CS4251_DAC_DIF_I2S_24		(1)		/* I2S, up to 24bit */
#define 	CS4251_DAC_DIF_RIGHT_24		(2)		/* right justified, 24bit */
#define 	CS4251_DAC_DIF_RIGHT_20		(3)		/* right justified, 20bit */
#define 	CS4251_DAC_DIF_RIGHT_18		(4)		/* right justified, 18bit */
#define 	CS4251_DAC_DIF_RIGHT_16		(5)		/* right justified, 16bit */
#define CS4251_REG04_ADC_I2S_LJ		(0x04)	/* ADC I2S or left justified */
#define CS4251_REG04_DIGMIX			(0x02)	/* digital mix */
#define CS4251_REG04_MICMIX			(0x01)	/* microphone mix */

#define CS4251_REG05_ADC_SNGVOL		(0x80)	/* ADC signal volume control */
#define CS4251_REG05_ADCB_DBOOST	(0x40)	/* ADC ch-B 20dB digital boost */
#define CS4251_REG05_ADCA_DBOOST	(0x20)	/* ADC ch-A 20dB digital boost */
#define CS4251_REG05_ADC_DBOOST_MASK (CS4251_REG05_ADCB_DBOOST | CS4251_REG05_ADCA_DBOOST)
#define CS4251_REG05_MICBIAS_SEL	(0x10)	/* 1=AIN2B pin, 0=AIN3B/MICIN2 pin */
#define CS4251_REG05_MICBIAS_LVL_MASK	(0x0c)	/* MIC bias level */
#define		CS4251_MICBIAS_LVL_08VA		(0)		/* 0.8 x VA */
#define		CS4251_MICBIAS_LVL_07VA		(1)		/* 0.7 x VA */
#define		CS4251_MICBIAS_LVL_06VA		(2)		/* 0.6 x VA */
#define		CS4251_MICBIAS_LVL_05VA		(3)		/* 0.5 x VA */
#define CS4251_REG05_MICB_BOOST		(0x02)	/* MIC ch-B preamplifier boost */
#define CS4251_REG05_MICA_BOOST		(0x01)	/* MIC ch-A preamplifier boost */
#define CS4251_REG05_MIC_BOOST_MASK		(CS4251_REG05_MICB_BOOST | CS4251_REG05_MICA_BOOST)

#define CS4251_REG06_ADCB_HPFEN	(0x80)	/* ADC ch-B high pass filter enable */
#define CS4251_REG06_ADCB_HPFRZ	(0x40)	/* ADC ch-B high pass filter freeze */
#define CS4251_REG06_ADCA_HPFEN	(0x20)	/* ADC ch-A high pass filter enable */
#define CS4251_REG06_ADCA_HPFRZ	(0x10)	/* ADC ch-A high pass filter freeze */
#define CS4251_REG06_ADC_HPFEN_MASK	(CS4251_REG06_ADCB_HPFEN | CS4251_REG06_ADCA_HPFEN)
#define CS4251_REG06_ADC_HPFRZ_MASK	(CS4251_REG06_ADCB_HPFRZ | CS4251_REG06_ADCA_HPFRZ)
#define CS4251_REG06_SOFTB		(0x08)	/* soft ramp ch-B control */
#define CS4251_REG06_ZCROSSB	(0x04)	/* zero cross ch-B control */
#define CS4251_REG06_SOFTA		(0x02)	/* soft ramp ch-A control */
#define CS4251_REG06_ZCROSSA	(0x01)	/* zero cross ch-A control */
#define CS4251_REG06_SOFT_MASK	 (CS4251_REG06_SOFTB | CS4251_REG06_SOFTA)
#define CS4251_REG06_ZCROSS_MSAK (CS4251_REG06_ZCROSSB | CS4251_REG06_ZCROSSA)

#define CS4251_REG07_AINB_MUX1	(0x80)	/* ADC ch-B input select1 */
#define CS4251_REG07_AINB_MUX0	(0x40)	/* ADC ch-B input select0 */
#define CS4251_REG07_AINA_MUX1	(0x20)	/* ADC ch-A input select1 */
#define CS4251_REG07_AINA_MUX0	(0x10)	/* ADC ch-A input select0 */
#define CS4251_REG07_AIN_MUX_MASK	(0xf0)
#define 	CS4251_AIN_MUX_PATH_AIN1			(0x00)
#define 	CS4251_AIN_MUX_PATH_AIN2			(0x50)
#define 	CS4251_AIN_MUX_PATH_AIN3			(0xa0)
#define 	CS4251_AIN_MUX_PATH_AIN3_PREAMP		(0xf0)
#define CS4251_REG07_INV_ADCB	(0x08)	/* ADC ch-B invert signal polarity */
#define CS4251_REG07_INV_ADCA	(0x04)	/* ADC ch-A invert signal polarity */
#define CS4251_REG07_ADCB_MUTE	(0x02)	/* ADC ch-B mute */
#define CS4251_REG07_ADCA_MUTE	(0x01)	/* ADC ch-A mute */
#define CS4251_REG07_ADC_MUTE_MASK	(CS4251_REG07_ADCB_MUTE | CS4251_REG07_ADCA_MUTE)

#define CS4251_REG08_HP_GAIN_MASK	(0xd0)	/* headphone analog gain */
#define 	CS4251_HP_GAIN_0			(0)		/* 0.3959 */
#define 	CS4251_HP_GAIN_1			(1)		/* 0.4571 */
#define 	CS4251_HP_GAIN_2			(2)		/* 0.5111 */
#define 	CS4251_HP_GAIN_3			(3)		/* 0.6047 */
#define 	CS4251_HP_GAIN_4			(4)		/* 0.7099 */
#define 	CS4251_HP_GAIN_5			(5)		/* 0.8399 */
#define 	CS4251_HP_GAIN_6			(6)		/* 1.0000 */
#define 	CS4251_HP_GAIN_7			(7)		/* 1.1430 */
#define CS4251_REG08_DAC_SNGVOL		(0x10)	/* DAC signal volume control */
#define CS4251_REG08_INV_PCMB		(0x08)	/* PCM ch-B invert signal polarity */
#define CS4251_REG08_INV_PCMA		(0x04)	/* PCM ch-A invert signal polarity */
#define CS4251_REG08_DACB_MUTE		(0x02)	/* DAC ch-B mute */
#define CS4251_REG08_DACA_MUTE		(0x01)	/* DAC ch-A mute */
#define CS4251_REG08_DAC_MUTE_MASK	(CS4251_REG08_DACB_MUTE | CS4251_REG08_DACA_MUTE)

#define CS4251_REG09_DATA_SEL_MASK	(0xc0)	/* DAC data selection */
#define 	CS4251_DATA_SEL_PCM			(0)		/* PCM serial port to DAC */
#define 	CS4251_DATA_SEL_SPE			(1)		/* Signal Processing Engine to DAC */
#define 	CS4251_DATA_SEL_ADC			(2)		/* ADC serial port to DAC */
#define CS4251_REG09_FREEZE			(0x20)	/* freeze controls */
#define CS4251_REG09_DEEMPH			(0x08)	/* DAC de-emphasis control */
#define CS4251_REG09_DAC_SZC_MASK	(0x03)	/* DAC soft ramp and zero cross control */
#define 	CS4251_DAC_SZC_IMMEDIATE	(0)		/* immediate change */
#define 	CS4251_DAC_SZC_ZEROCROSS	(1)		/* zero cross */
#define 	CS4251_DAC_SZC_SOFTRAMP		(2)		/* soft ramp */
#define 	CS4251_DAC_SZC_SOFTRAMP_ZC	(3)		/* soft ramp on zero crossings */

#define CS4251_REG0A_ALCA_SRDIS	(0x80)	/* ALC ch-A soft ramp disable */
#define CS4251_REG0A_ALCA_ZCDIS	(0x40)	/* ALC ch-A zero cross disable */
#define CS4251_REG0A_PGAA_VOL_MASK	(0x1f)	/* PGA ch-A gain control */

#define CS4251_REG0B_ALCB_SRDIS	(0x80)	/* ALC ch-B soft ramp disable */
#define CS4251_REG0B_ALCB_ZCDIS	(0x40)	/* ALC ch-B zero cross disable */
#define CS4251_REG0B_PGAB_VOL_MASK	(0x1f)	/* PGA ch-B gain control */

#define CS4251_REG0C_ADCA_ATT_MASK	(0xff)	/* ADC ch-A attenuation control */
#define CS4251_REG0D_ADCB_ATT_MASK	(0xff)	/* ADC ch-B attenuation control */
#define 	CS4251_ADC_ATT_MIN			(0)		/*   0dB */
#define 	CS4251_ADC_ATT_MAX			(-96)	/* -96dB */

#define CS4251_REG0E_MUTE_ADCMIXA		(0x80)	/* ADC ch-A mixer channel mute */
#define CS4251_REG0E_ADCMIXA_VOL_MASK	(0x7f)	/* ADC ch-A mixer volume control */

#define CS4251_REG0F_MUTE_ADCMIXB		(0x80)	/* ADC ch-B mixer channel mute */
#define CS4251_REG0F_ADCMIXB_VOL_MASK	(0x7f)	/* ADC ch-B mixer volume control */

#define CS4251_REG10_MUTE_PCMMIXA		(0x80)	/* PCM ch-A mixer channel mute */
#define CS4251_REG10_PCMMIXA_VOL_MASK	(0x7f)	/* PCM ch-A mixer volume control */

#define CS4251_REG11_MUTE_PCMMIXB		(0x80)	/* PCM ch-B mixer channel mute */
#define CS4251_REG11_PCMMIXB_VOL_MASK	(0x7f)	/* PCM ch-B mixer volume control */

#define CS4251_REG12_FREQ_MASK		(0xf0)	/* beep frequency */
#define CS4251_REG12_ONTIME_MASK	(0x0f)	/* beep on time duration */

#define CS4251_REG13_OFFTIME_MASK	(0xe0)	/* beep off time */
#define CS4251_REG13_BPVOL_MASK	(0x1f)	/* beep volume */

#define CS4251_REG14_REPEAT			(0x80)	/* repeat beep */
#define CS4251_REG14_BEEP			(0x40)	/* beep */
#define CS4251_REG14_CONT_BEEP_MASK	(CS4251_REG14_REPEAT | CS4251_REG14_BEEP)
#define CS4251_REG14_TREB_CF_MASK	(0x18)	/* treble corner frequency */
#define 	CS4251_TREB_CF_5KHZ		(0)		/* 5kHz */
#define 	CS4251_TREB_CF_7KHZ		(1)		/* 7kHz */
#define 	CS4251_TREB_CF_10KHZ		(2)		/* 10kHz */
#define 	CS4251_TREB_CF_15KHZ		(3)		/* 15kHz */
#define CS4251_REG14_BASS_CF_MASK	(0x06)	/* bass corner frequency */
#define 	CS4251_BASS_CF_50HZ		(0)		/* 50Hz */
#define 	CS4251_BASS_CF_100HZ		(1)		/* 100Hz */
#define 	CS4251_BASS_CF_200HZ		(2)		/* 200Hz */
#define 	CS4251_BASS_CF_250HZ		(3)		/* 250Hz */
#define CS4251_REG14_TC_EN			(0x01)	/* tone control enable */

#define CS4251_REG15_TREB_MASK		(0xf0)	/* treble gain level */
#define CS4251_REG15_BASS_MASK		(0x0f)	/* bass gain level */

#define CS4251_REG16_AOUTA_VOL_MASK	(0xff)	/* AOUT ch-A volume control */
#define CS4251_REG17_AOUTB_VOL_MASK	(0xff)	/* AOUT ch-B volume control */

#define CS4251_REG18_PCMA_MASK		(0xc0)	/*  */
#define CS4251_REG18_PCMB_MASK		(0x30)	/*  */
#define CS4251_REG18_ADCA_MASK		(0x0c)	/*  */
#define CS4251_REG18_ADCB_MASK		(0x03)	/*  */

#define CS4251_REG19_MAX_MASK		(0xe0)	/* maximum threshold */
#define CS4251_REG19_CUSH_MASK		(0x1c)	/* cushion threshold */
#define CS4251_REG19_LIM_SRDIS		(0x02)	/* limiter soft ramp disable */
#define CS4251_REG19_LIM_ZCDIS		(0x01)	/* limiter zero cross disable */

#define CS4251_REG1A_LIMIT_EN		(0x80)	/* peak detect and limiter enable */
#define CS4251_REG1A_LIMIT_ALL		(0x40)	/* peak signal limit all channels */
#define CS4251_REG1A_RRATE_MASK		(0x3f)	/* limiter release rate */
#define 	CS4251_RATE_FASTEST		(0x00)	/* fastest */
#define 	CS4251_RATE_SLOWEST		(0x3f)	/* slowest */

#define CS4251_REG1B_ARATE_MASK	(0x3f)	/* limiter attack rate */

#define CS4251_REG1C_ALC_ENB		(0x80)	/* ALC ch-B enable */
#define CS4251_REG1C_ALC_ENA		(0x40)	/* ALC ch-A enable */
#define CS4251_REG1C_ALC_ARATE_MASK	(0x3f)	/* ALC attack rate */

#define CS4251_REG1D_ALC_RRATE_MASK	(0x3f)	/* ALC release rate */

#define CS4251_REG1E_MAX_MASK		(0xe0)	/* maximum threshold */
#define CS4251_REG1E_MIN_MASK		(0x1c)	/* minimum threshold */

#define CS4251_REG1F_NG_ALL			(0x80)	/* noise gate channel gang */
#define CS4251_REG1F_NG_EN			(0x40)	/* noise gate enable */
#define CS4251_REG1F_NG_BOOST		(0x20)	/* noise gate boost */
#define CS4251_REG1F_THRESH_MASK	(0x1c)	/* threshold */
#define CS4251_REG1F_NGDELAY_MASK	(0x03)	/* noise gate delay timing */

#define CS4251_REG20_SP_CLKERR		(0x40)	/* serial port clock error */
#define CS4251_REG20_SPEA_OVFL		(0x20)	/* SPE ch-A over flow */
#define CS4251_REG20_SPEB_OVFL		(0x10)	/* SPE ch-B over flow */
#define CS4251_REG20_PCMA_OVFL		(0x08)	/* PCM ch-A over flow */
#define CS4251_REG20_PCMB_OVFL		(0x04)	/* PCM ch-B over flow */
#define CS4251_REG20_ADCA_OVFL		(0x02)	/* ADC ch-A over flow */
#define CS4251_REG20_ADCB_OVFL		(0x01)	/* ADC ch-B over flow */

#define CS4251_REG21_CHRG_FREQ_MASK	(0xf0)	/* charge pump frequency */

/* audio interface data formats */
typedef enum {
	fmt_16to24bit_left_slave = 0, /* 16 to 24bit, left justified, slave mode */
 	fmt_16to24bit_I2S		 = 1, /* 16 to 24bit, I2S */
	fmt_24bit_right			 = 2, /* 24bit, right justified */
	fmt_20bit_right			 = 3, /* 20bit, right justified */
	fmt_16bit_right			 = 4, /* 16bit, right justified */
	fmt_16to24bit_left_master= 5  /* 16 to 24bit, left justified, master mode */
} pcm1772_audio_data_format_t;

/* read a data from register */
extern int	cs4251_read_reg(int reg, unsigned char *data);

/* write a data to register */
extern int	cs4251_write_reg(int reg, unsigned char data);

/* read modify write to register */
extern int	cs4251_modify_reg(int reg, unsigned char mask, unsigned char value);

/* restore registeres */
extern int	cs4251_restore_regs(void);

#define cs4251_set_powerdown_dac(flag) \
	cs4251_modify_reg(0x02, CS4251_REG02_PDN_DAC_MASK, (flag) ? CS4251_REG02_PDN_DAC_MASK : 0)

#define cs4251_set_powerdown_pga(flag) \
	cs4251_modify_reg(0x02, CS4251_REG02_PDN_PGA_MASK, (flag) ? CS4251_REG02_PDN_PGA_MASK : 0)

#define cs4251_set_powerdown_adc(flag) \
	cs4251_modify_reg(0x02, CS4251_REG02_PDN_ADC_MASK, (flag) ? CS4251_REG02_PDN_ADC_MASK : 0)

#define cs4251_set_powerdown(flag) \
	cs4251_modify_reg(0x02, CS4251_REG02_PDN, (flag) << 0)

#define cs4251_set_powerdown_mic(flag) \
	cs4251_modify_reg(0x03, CS4251_REG03_PDN_MIC_MASK, (flag) ? CS4251_REG03_PDN_MIC_MASK : 0)

#define cs4251_set_powerdown_micbias(flag) \
	cs4251_modify_reg(0x03, CS4251_REG03_PDN_MICBIAS, (flag) << 1)

#define cs4251_set_adc_path(path) \
	cs4251_modify_reg(0x07, CS4251_REG07_AIN_MUX_MASK, (path))

#define cs4251_set_adc_mute(flag) \
	cs4251_modify_reg(0x07, CS4251_REG07_ADC_MUTE_MASK, (flag) ? CS4251_REG07_ADC_MUTE_MASK : 0)

#define cs4251_set_dac_mute(flag) \
	cs4251_modify_reg(0x08, CS4251_REG08_DAC_MUTE_MASK, (flag) ? CS4251_REG08_DAC_MUTE_MASK : 0)

extern int cs4251_set_pga_vol(int a_ch, int b_ch);

extern int cs4251_set_mute_adc_mix(bool_t flag);
extern int cs4251_set_adc_mix_vol(int a_ch, int b_ch);

extern int cs4251_set_mute_pcm_mix(bool_t flag);
extern int cs4251_set_pcm_mix_vol(int a_ch, int b_ch);

#define cs4251_set_beep_freq(level) \
	cs4251_modify_reg(0x12, CS4251_REG12_FREQ_MASK, (level) << 4)

#define cs4251_set_beep_vol(vol) \
	cs4251_modify_reg(0x13, CS4251_REG13_BPVOL_MASK, (vol))

#define cs4251_set_cont_beep(flag) \
	cs4251_modify_reg(0x14, CS4251_REG14_CONT_BEEP_MASK, (flag) ? CS4251_REG14_CONT_BEEP_MASK : 0)

#define cs4251_set_repeat_beep(flag) \
	cs4251_modify_reg(0x14, CS4251_REG14_REPEAT, (flag) << 7)

#define cs4251_set_beep(flag) \
	cs4251_modify_reg(0x14, CS4251_REG14_BEEP, (flag) << 6)

#define cs4251_set_tone_enable(flag) \
	cs4251_modify_reg(0x14, CS4251_REG14_TC_EN, (flag) << 0)

/* set treble level (0:+12dB to 15:-10.5dB, a step is 1.5dB) */
#define cs4251_set_treble(level) \
	cs4251_modify_reg(0x15, CS4251_REG15_TREB_MASK, (level) << 4)

/* set bass level (0:+12dB to 15:-10.5dB, a step is 1.5dB) */
#define cs4251_set_bass(level) \
	cs4251_modify_reg(0x15, CS4251_REG15_BASS_MASK, (level))

/* set analog output volume */
extern int cs4251_set_aout_vol(int a_ch, int b_ch);

#endif /* CS4251_H */
