162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci#ifndef __SOUND_WSS_H
362306a36Sopenharmony_ci#define __SOUND_WSS_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
762306a36Sopenharmony_ci *  Definitions for CS4231 & InterWave chips & compatible chips
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <sound/control.h>
1162306a36Sopenharmony_ci#include <sound/pcm.h>
1262306a36Sopenharmony_ci#include <sound/timer.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <sound/cs4231-regs.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* defines for codec.mode */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define WSS_MODE_NONE	0x0000
1962306a36Sopenharmony_ci#define WSS_MODE_PLAY	0x0001
2062306a36Sopenharmony_ci#define WSS_MODE_RECORD	0x0002
2162306a36Sopenharmony_ci#define WSS_MODE_TIMER	0x0004
2262306a36Sopenharmony_ci#define WSS_MODE_OPEN	(WSS_MODE_PLAY|WSS_MODE_RECORD|WSS_MODE_TIMER)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* defines for codec.hardware */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define WSS_HW_DETECT        0x0000	/* let CS4231 driver detect chip */
2762306a36Sopenharmony_ci#define WSS_HW_DETECT3	0x0001	/* allow mode 3 */
2862306a36Sopenharmony_ci#define WSS_HW_TYPE_MASK	0xff00	/* type mask */
2962306a36Sopenharmony_ci#define WSS_HW_CS4231_MASK   0x0100	/* CS4231 serie */
3062306a36Sopenharmony_ci#define WSS_HW_CS4231        0x0100	/* CS4231 chip */
3162306a36Sopenharmony_ci#define WSS_HW_CS4231A       0x0101	/* CS4231A chip */
3262306a36Sopenharmony_ci#define WSS_HW_AD1845	0x0102	/* AD1845 chip */
3362306a36Sopenharmony_ci#define WSS_HW_CS4232_MASK   0x0200	/* CS4232 serie (has control ports) */
3462306a36Sopenharmony_ci#define WSS_HW_CS4232        0x0200	/* CS4232 */
3562306a36Sopenharmony_ci#define WSS_HW_CS4232A       0x0201	/* CS4232A */
3662306a36Sopenharmony_ci#define WSS_HW_CS4236	0x0202	/* CS4236 */
3762306a36Sopenharmony_ci#define WSS_HW_CS4236B_MASK	0x0400	/* CS4236B serie (has extended control regs) */
3862306a36Sopenharmony_ci#define WSS_HW_CS4235	0x0400	/* CS4235 - Crystal Clear (tm) stereo enhancement */
3962306a36Sopenharmony_ci#define WSS_HW_CS4236B       0x0401	/* CS4236B */
4062306a36Sopenharmony_ci#define WSS_HW_CS4237B       0x0402	/* CS4237B - SRS 3D */
4162306a36Sopenharmony_ci#define WSS_HW_CS4238B	0x0403	/* CS4238B - QSOUND 3D */
4262306a36Sopenharmony_ci#define WSS_HW_CS4239	0x0404	/* CS4239 - Crystal Clear (tm) stereo enhancement */
4362306a36Sopenharmony_ci#define WSS_HW_AD1848_MASK	0x0800	/* AD1848 serie (half duplex) */
4462306a36Sopenharmony_ci#define WSS_HW_AD1847		0x0801	/* AD1847 chip */
4562306a36Sopenharmony_ci#define WSS_HW_AD1848		0x0802	/* AD1848 chip */
4662306a36Sopenharmony_ci#define WSS_HW_CS4248		0x0803	/* CS4248 chip */
4762306a36Sopenharmony_ci#define WSS_HW_CMI8330		0x0804	/* CMI8330 chip */
4862306a36Sopenharmony_ci#define WSS_HW_THINKPAD		0x0805	/* Thinkpad 360/750/755 */
4962306a36Sopenharmony_ci/* compatible, but clones */
5062306a36Sopenharmony_ci#define WSS_HW_INTERWAVE     0x1000	/* InterWave chip */
5162306a36Sopenharmony_ci#define WSS_HW_OPL3SA2       0x1101	/* OPL3-SA2 chip, similar to cs4231 */
5262306a36Sopenharmony_ci#define WSS_HW_OPTI93X 	0x1102	/* Opti 930/931/933 */
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* defines for codec.hwshare */
5562306a36Sopenharmony_ci#define WSS_HWSHARE_IRQ	(1<<0)
5662306a36Sopenharmony_ci#define WSS_HWSHARE_DMA1	(1<<1)
5762306a36Sopenharmony_ci#define WSS_HWSHARE_DMA2	(1<<2)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* IBM Thinkpad specific stuff */
6062306a36Sopenharmony_ci#define AD1848_THINKPAD_CTL_PORT1		0x15e8
6162306a36Sopenharmony_ci#define AD1848_THINKPAD_CTL_PORT2		0x15e9
6262306a36Sopenharmony_ci#define AD1848_THINKPAD_CS4248_ENABLE_BIT	0x02
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct snd_wss {
6562306a36Sopenharmony_ci	unsigned long port;		/* base i/o port */
6662306a36Sopenharmony_ci	struct resource *res_port;
6762306a36Sopenharmony_ci	unsigned long cport;		/* control base i/o port (CS4236) */
6862306a36Sopenharmony_ci	struct resource *res_cport;
6962306a36Sopenharmony_ci	int irq;			/* IRQ line */
7062306a36Sopenharmony_ci	int dma1;			/* playback DMA */
7162306a36Sopenharmony_ci	int dma2;			/* record DMA */
7262306a36Sopenharmony_ci	unsigned short version;		/* version of CODEC chip */
7362306a36Sopenharmony_ci	unsigned short mode;		/* see to WSS_MODE_XXXX */
7462306a36Sopenharmony_ci	unsigned short hardware;	/* see to WSS_HW_XXXX */
7562306a36Sopenharmony_ci	unsigned short hwshare;		/* shared resources */
7662306a36Sopenharmony_ci	unsigned short single_dma:1,	/* forced single DMA mode (GUS 16-bit */
7762306a36Sopenharmony_ci					/* daughter board) or dma1 == dma2 */
7862306a36Sopenharmony_ci		       ebus_flag:1,	/* SPARC: EBUS present */
7962306a36Sopenharmony_ci		       thinkpad_flag:1;	/* Thinkpad CS4248 needs extra help */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	struct snd_card *card;
8262306a36Sopenharmony_ci	struct snd_pcm *pcm;
8362306a36Sopenharmony_ci	struct snd_pcm_substream *playback_substream;
8462306a36Sopenharmony_ci	struct snd_pcm_substream *capture_substream;
8562306a36Sopenharmony_ci	struct snd_timer *timer;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	unsigned char image[32];	/* registers image */
8862306a36Sopenharmony_ci	unsigned char eimage[32];	/* extended registers image */
8962306a36Sopenharmony_ci	unsigned char cimage[16];	/* control registers image */
9062306a36Sopenharmony_ci	int mce_bit;
9162306a36Sopenharmony_ci	int calibrate_mute;
9262306a36Sopenharmony_ci	int sw_3d_bit;
9362306a36Sopenharmony_ci	unsigned int p_dma_size;
9462306a36Sopenharmony_ci	unsigned int c_dma_size;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	spinlock_t reg_lock;
9762306a36Sopenharmony_ci	struct mutex mce_mutex;
9862306a36Sopenharmony_ci	struct mutex open_mutex;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	int (*rate_constraint) (struct snd_pcm_runtime *runtime);
10162306a36Sopenharmony_ci	void (*set_playback_format) (struct snd_wss *chip,
10262306a36Sopenharmony_ci				     struct snd_pcm_hw_params *hw_params,
10362306a36Sopenharmony_ci				     unsigned char pdfr);
10462306a36Sopenharmony_ci	void (*set_capture_format) (struct snd_wss *chip,
10562306a36Sopenharmony_ci				    struct snd_pcm_hw_params *hw_params,
10662306a36Sopenharmony_ci				    unsigned char cdfr);
10762306a36Sopenharmony_ci	void (*trigger) (struct snd_wss *chip, unsigned int what, int start);
10862306a36Sopenharmony_ci#ifdef CONFIG_PM
10962306a36Sopenharmony_ci	void (*suspend) (struct snd_wss *chip);
11062306a36Sopenharmony_ci	void (*resume) (struct snd_wss *chip);
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci	void *dma_private_data;
11362306a36Sopenharmony_ci	int (*claim_dma) (struct snd_wss *chip,
11462306a36Sopenharmony_ci			  void *dma_private_data, int dma);
11562306a36Sopenharmony_ci	int (*release_dma) (struct snd_wss *chip,
11662306a36Sopenharmony_ci			    void *dma_private_data, int dma);
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/* exported functions */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_civoid snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char val);
12262306a36Sopenharmony_ciunsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg);
12362306a36Sopenharmony_civoid snd_cs4236_ext_out(struct snd_wss *chip,
12462306a36Sopenharmony_ci			unsigned char reg, unsigned char val);
12562306a36Sopenharmony_ciunsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg);
12662306a36Sopenharmony_civoid snd_wss_mce_up(struct snd_wss *chip);
12762306a36Sopenharmony_civoid snd_wss_mce_down(struct snd_wss *chip);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_civoid snd_wss_overrange(struct snd_wss *chip);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciirqreturn_t snd_wss_interrupt(int irq, void *dev_id);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciconst char *snd_wss_chip_id(struct snd_wss *chip);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciint snd_wss_create(struct snd_card *card,
13662306a36Sopenharmony_ci		      unsigned long port,
13762306a36Sopenharmony_ci		      unsigned long cport,
13862306a36Sopenharmony_ci		      int irq, int dma1, int dma2,
13962306a36Sopenharmony_ci		      unsigned short hardware,
14062306a36Sopenharmony_ci		      unsigned short hwshare,
14162306a36Sopenharmony_ci		      struct snd_wss **rchip);
14262306a36Sopenharmony_ciint snd_wss_pcm(struct snd_wss *chip, int device);
14362306a36Sopenharmony_ciint snd_wss_timer(struct snd_wss *chip, int device);
14462306a36Sopenharmony_ciint snd_wss_mixer(struct snd_wss *chip);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciconst struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciint snd_cs4236_create(struct snd_card *card,
14962306a36Sopenharmony_ci		      unsigned long port,
15062306a36Sopenharmony_ci		      unsigned long cport,
15162306a36Sopenharmony_ci		      int irq, int dma1, int dma2,
15262306a36Sopenharmony_ci		      unsigned short hardware,
15362306a36Sopenharmony_ci		      unsigned short hwshare,
15462306a36Sopenharmony_ci		      struct snd_wss **rchip);
15562306a36Sopenharmony_ciint snd_cs4236_pcm(struct snd_wss *chip, int device);
15662306a36Sopenharmony_ciint snd_cs4236_mixer(struct snd_wss *chip);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci *  mixer library
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define WSS_SINGLE(xname, xindex, reg, shift, mask, invert) \
16362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
16462306a36Sopenharmony_ci  .name = xname, \
16562306a36Sopenharmony_ci  .index = xindex, \
16662306a36Sopenharmony_ci  .info = snd_wss_info_single, \
16762306a36Sopenharmony_ci  .get = snd_wss_get_single, \
16862306a36Sopenharmony_ci  .put = snd_wss_put_single, \
16962306a36Sopenharmony_ci  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ciint snd_wss_info_single(struct snd_kcontrol *kcontrol,
17262306a36Sopenharmony_ci			struct snd_ctl_elem_info *uinfo);
17362306a36Sopenharmony_ciint snd_wss_get_single(struct snd_kcontrol *kcontrol,
17462306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol);
17562306a36Sopenharmony_ciint snd_wss_put_single(struct snd_kcontrol *kcontrol,
17662306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define WSS_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
17962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
18062306a36Sopenharmony_ci  .name = xname, \
18162306a36Sopenharmony_ci  .index = xindex, \
18262306a36Sopenharmony_ci  .info = snd_wss_info_double, \
18362306a36Sopenharmony_ci  .get = snd_wss_get_double, \
18462306a36Sopenharmony_ci  .put = snd_wss_put_double, \
18562306a36Sopenharmony_ci  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
18662306a36Sopenharmony_ci		   (shift_right << 19) | (mask << 24) | (invert << 22) }
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci#define WSS_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
18962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
19062306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
19162306a36Sopenharmony_ci  .name = xname, \
19262306a36Sopenharmony_ci  .index = xindex, \
19362306a36Sopenharmony_ci  .info = snd_wss_info_single, \
19462306a36Sopenharmony_ci  .get = snd_wss_get_single, \
19562306a36Sopenharmony_ci  .put = snd_wss_put_single, \
19662306a36Sopenharmony_ci  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
19762306a36Sopenharmony_ci  .tlv = { .p = (xtlv) } }
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define WSS_DOUBLE_TLV(xname, xindex, left_reg, right_reg, \
20062306a36Sopenharmony_ci			shift_left, shift_right, mask, invert, xtlv) \
20162306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
20262306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
20362306a36Sopenharmony_ci  .name = xname, \
20462306a36Sopenharmony_ci  .index = xindex, \
20562306a36Sopenharmony_ci  .info = snd_wss_info_double, \
20662306a36Sopenharmony_ci  .get = snd_wss_get_double, \
20762306a36Sopenharmony_ci  .put = snd_wss_put_double, \
20862306a36Sopenharmony_ci  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
20962306a36Sopenharmony_ci		   (shift_right << 19) | (mask << 24) | (invert << 22), \
21062306a36Sopenharmony_ci  .tlv = { .p = (xtlv) } }
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciint snd_wss_info_double(struct snd_kcontrol *kcontrol,
21462306a36Sopenharmony_ci			struct snd_ctl_elem_info *uinfo);
21562306a36Sopenharmony_ciint snd_wss_get_double(struct snd_kcontrol *kcontrol,
21662306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol);
21762306a36Sopenharmony_ciint snd_wss_put_double(struct snd_kcontrol *kcontrol,
21862306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#endif /* __SOUND_WSS_H */
221