0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/module.h>
0034 #include <linux/kernel.h>
0035 #include <linux/slab.h>
0036 #include <linux/init.h>
0037 #include <linux/interrupt.h>
0038 #include <linux/moduleparam.h>
0039 #include <linux/of.h>
0040 #include <linux/of_device.h>
0041 #include <linux/io.h>
0042
0043 #include <sound/core.h>
0044 #include <sound/pcm.h>
0045 #include <sound/info.h>
0046 #include <sound/control.h>
0047 #include <sound/initval.h>
0048
0049 #include <asm/irq.h>
0050 #include <asm/prom.h>
0051
0052 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
0053 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
0054 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
0055
0056 module_param_array(index, int, NULL, 0444);
0057 MODULE_PARM_DESC(index, "Index value for Sun AMD7930 soundcard.");
0058 module_param_array(id, charp, NULL, 0444);
0059 MODULE_PARM_DESC(id, "ID string for Sun AMD7930 soundcard.");
0060 module_param_array(enable, bool, NULL, 0444);
0061 MODULE_PARM_DESC(enable, "Enable Sun AMD7930 soundcard.");
0062 MODULE_AUTHOR("Thomas K. Dyas and David S. Miller");
0063 MODULE_DESCRIPTION("Sun AMD7930");
0064 MODULE_LICENSE("GPL");
0065
0066
0067
0068
0069 #define AMD7930_CR 0x00UL
0070 #define AMD7930_IR AMD7930_CR
0071 #define AMD7930_DR 0x01UL
0072 #define AMD7930_DSR1 0x02UL
0073 #define AMD7930_DER 0x03UL
0074 #define AMD7930_DCTB 0x04UL
0075 #define AMD7930_DCRB AMD7930_DCTB
0076 #define AMD7930_BBTB 0x05UL
0077 #define AMD7930_BBRB AMD7930_BBTB
0078 #define AMD7930_BCTB 0x06UL
0079 #define AMD7930_BCRB AMD7930_BCTB
0080 #define AMD7930_DSR2 0x07UL
0081
0082
0083 struct amd7930_map {
0084 __u16 x[8];
0085 __u16 r[8];
0086 __u16 gx;
0087 __u16 gr;
0088 __u16 ger;
0089 __u16 stgr;
0090 __u16 ftgr;
0091 __u16 atgr;
0092 __u8 mmr1;
0093 __u8 mmr2;
0094 };
0095
0096
0097
0098
0099
0100
0101 #define AMR_IR_DTTHRSH 0x01
0102 #define AMR_IR_DRTHRSH 0x02
0103 #define AMR_IR_DSRI 0x04
0104 #define AMR_IR_DERI 0x08
0105 #define AMR_IR_BBUF 0x10
0106 #define AMR_IR_LSRI 0x20
0107 #define AMR_IR_DSR2I 0x40
0108 #define AMR_IR_MLTFRMI 0x80
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118 #define AMR_INIT 0x21
0119 #define AM_INIT_ACTIVE 0x01
0120 #define AM_INIT_DATAONLY 0x02
0121 #define AM_INIT_POWERDOWN 0x03
0122 #define AM_INIT_DISABLE_INTS 0x04
0123 #define AMR_INIT2 0x20
0124 #define AM_INIT2_ENABLE_POWERDOWN 0x20
0125 #define AM_INIT2_ENABLE_MULTIFRAME 0x10
0126
0127
0128 #define AMR_LIU_LSR 0xA1
0129 #define AM_LIU_LSR_STATE 0x07
0130 #define AM_LIU_LSR_F3 0x08
0131 #define AM_LIU_LSR_F7 0x10
0132 #define AM_LIU_LSR_F8 0x20
0133 #define AM_LIU_LSR_HSW 0x40
0134 #define AM_LIU_LSR_HSW_CHG 0x80
0135 #define AMR_LIU_LPR 0xA2
0136 #define AMR_LIU_LMR1 0xA3
0137 #define AM_LIU_LMR1_B1_ENABL 0x01
0138 #define AM_LIU_LMR1_B2_ENABL 0x02
0139 #define AM_LIU_LMR1_F_DISABL 0x04
0140 #define AM_LIU_LMR1_FA_DISABL 0x08
0141 #define AM_LIU_LMR1_REQ_ACTIV 0x10
0142 #define AM_LIU_LMR1_F8_F3 0x20
0143 #define AM_LIU_LMR1_LIU_ENABL 0x40
0144 #define AMR_LIU_LMR2 0xA4
0145 #define AM_LIU_LMR2_DECHO 0x01
0146 #define AM_LIU_LMR2_DLOOP 0x02
0147 #define AM_LIU_LMR2_DBACKOFF 0x04
0148 #define AM_LIU_LMR2_EN_F3_INT 0x08
0149 #define AM_LIU_LMR2_EN_F8_INT 0x10
0150 #define AM_LIU_LMR2_EN_HSW_INT 0x20
0151 #define AM_LIU_LMR2_EN_F7_INT 0x40
0152 #define AMR_LIU_2_4 0xA5
0153 #define AMR_LIU_MF 0xA6
0154 #define AMR_LIU_MFSB 0xA7
0155 #define AMR_LIU_MFQB 0xA8
0156
0157
0158 #define AMR_MUX_MCR1 0x41
0159 #define AMR_MUX_MCR2 0x42
0160 #define AMR_MUX_MCR3 0x43
0161 #define AM_MUX_CHANNEL_B1 0x01
0162 #define AM_MUX_CHANNEL_B2 0x02
0163 #define AM_MUX_CHANNEL_Ba 0x03
0164 #define AM_MUX_CHANNEL_Bb 0x04
0165 #define AM_MUX_CHANNEL_Bc 0x05
0166 #define AM_MUX_CHANNEL_Bd 0x06
0167 #define AM_MUX_CHANNEL_Be 0x07
0168 #define AM_MUX_CHANNEL_Bf 0x08
0169 #define AMR_MUX_MCR4 0x44
0170 #define AM_MUX_MCR4_ENABLE_INTS 0x08
0171 #define AM_MUX_MCR4_REVERSE_Bb 0x10
0172 #define AM_MUX_MCR4_REVERSE_Bc 0x20
0173 #define AMR_MUX_1_4 0x45
0174
0175
0176 #define AMR_MAP_X 0x61
0177 #define AMR_MAP_R 0x62
0178 #define AMR_MAP_GX 0x63
0179 #define AMR_MAP_GR 0x64
0180 #define AMR_MAP_GER 0x65
0181 #define AMR_MAP_STGR 0x66
0182 #define AMR_MAP_FTGR_1_2 0x67
0183 #define AMR_MAP_ATGR_1_2 0x68
0184 #define AMR_MAP_MMR1 0x69
0185 #define AM_MAP_MMR1_ALAW 0x01
0186 #define AM_MAP_MMR1_GX 0x02
0187 #define AM_MAP_MMR1_GR 0x04
0188 #define AM_MAP_MMR1_GER 0x08
0189 #define AM_MAP_MMR1_X 0x10
0190 #define AM_MAP_MMR1_R 0x20
0191 #define AM_MAP_MMR1_STG 0x40
0192 #define AM_MAP_MMR1_LOOPBACK 0x80
0193 #define AMR_MAP_MMR2 0x6A
0194 #define AM_MAP_MMR2_AINB 0x01
0195 #define AM_MAP_MMR2_LS 0x02
0196 #define AM_MAP_MMR2_ENABLE_DTMF 0x04
0197 #define AM_MAP_MMR2_ENABLE_TONEGEN 0x08
0198 #define AM_MAP_MMR2_ENABLE_TONERING 0x10
0199 #define AM_MAP_MMR2_DISABLE_HIGHPASS 0x20
0200 #define AM_MAP_MMR2_DISABLE_AUTOZERO 0x40
0201 #define AMR_MAP_1_10 0x6B
0202 #define AMR_MAP_MMR3 0x6C
0203 #define AMR_MAP_STRA 0x6D
0204 #define AMR_MAP_STRF 0x6E
0205 #define AMR_MAP_PEAKX 0x70
0206 #define AMR_MAP_PEAKR 0x71
0207 #define AMR_MAP_15_16 0x72
0208
0209
0210 #define AMR_DLC_FRAR_1_2_3 0x81
0211 #define AMR_DLC_SRAR_1_2_3 0x82
0212 #define AMR_DLC_TAR 0x83
0213 #define AMR_DLC_DRLR 0x84
0214 #define AMR_DLC_DTCR 0x85
0215 #define AMR_DLC_DMR1 0x86
0216 #define AMR_DLC_DMR1_DTTHRSH_INT 0x01
0217 #define AMR_DLC_DMR1_DRTHRSH_INT 0x02
0218 #define AMR_DLC_DMR1_TAR_ENABL 0x04
0219 #define AMR_DLC_DMR1_EORP_INT 0x08
0220 #define AMR_DLC_DMR1_EN_ADDR1 0x10
0221 #define AMR_DLC_DMR1_EN_ADDR2 0x20
0222 #define AMR_DLC_DMR1_EN_ADDR3 0x40
0223 #define AMR_DLC_DMR1_EN_ADDR4 0x80
0224 #define AMR_DLC_DMR1_EN_ADDRS 0xf0
0225 #define AMR_DLC_DMR2 0x87
0226 #define AMR_DLC_DMR2_RABRT_INT 0x01
0227 #define AMR_DLC_DMR2_RESID_INT 0x02
0228 #define AMR_DLC_DMR2_COLL_INT 0x04
0229 #define AMR_DLC_DMR2_FCS_INT 0x08
0230 #define AMR_DLC_DMR2_OVFL_INT 0x10
0231 #define AMR_DLC_DMR2_UNFL_INT 0x20
0232 #define AMR_DLC_DMR2_OVRN_INT 0x40
0233 #define AMR_DLC_DMR2_UNRN_INT 0x80
0234 #define AMR_DLC_1_7 0x88
0235 #define AMR_DLC_DRCR 0x89
0236 #define AMR_DLC_RNGR1 0x8A
0237 #define AMR_DLC_RNGR2 0x8B
0238 #define AMR_DLC_FRAR4 0x8C
0239 #define AMR_DLC_SRAR4 0x8D
0240 #define AMR_DLC_DMR3 0x8E
0241 #define AMR_DLC_DMR3_VA_INT 0x01
0242 #define AMR_DLC_DMR3_EOTP_INT 0x02
0243 #define AMR_DLC_DMR3_LBRP_INT 0x04
0244 #define AMR_DLC_DMR3_RBA_INT 0x08
0245 #define AMR_DLC_DMR3_LBT_INT 0x10
0246 #define AMR_DLC_DMR3_TBE_INT 0x20
0247 #define AMR_DLC_DMR3_RPLOST_INT 0x40
0248 #define AMR_DLC_DMR3_KEEP_FCS 0x80
0249 #define AMR_DLC_DMR4 0x8F
0250 #define AMR_DLC_DMR4_RCV_1 0x00
0251 #define AMR_DLC_DMR4_RCV_2 0x01
0252 #define AMR_DLC_DMR4_RCV_4 0x02
0253 #define AMR_DLC_DMR4_RCV_8 0x03
0254 #define AMR_DLC_DMR4_RCV_16 0x01
0255 #define AMR_DLC_DMR4_RCV_24 0x02
0256 #define AMR_DLC_DMR4_RCV_30 0x03
0257 #define AMR_DLC_DMR4_XMT_1 0x00
0258 #define AMR_DLC_DMR4_XMT_2 0x04
0259 #define AMR_DLC_DMR4_XMT_4 0x08
0260 #define AMR_DLC_DMR4_XMT_8 0x0c
0261 #define AMR_DLC_DMR4_XMT_10 0x08
0262 #define AMR_DLC_DMR4_XMT_14 0x0c
0263 #define AMR_DLC_DMR4_IDLE_MARK 0x00
0264 #define AMR_DLC_DMR4_IDLE_FLAG 0x10
0265 #define AMR_DLC_DMR4_ADDR_BOTH 0x00
0266 #define AMR_DLC_DMR4_ADDR_1ST 0x20
0267 #define AMR_DLC_DMR4_ADDR_2ND 0xa0
0268 #define AMR_DLC_DMR4_CR_ENABLE 0x40
0269 #define AMR_DLC_12_15 0x90
0270 #define AMR_DLC_ASR 0x91
0271 #define AMR_DLC_EFCR 0x92
0272 #define AMR_DLC_EFCR_EXTEND_FIFO 0x01
0273 #define AMR_DLC_EFCR_SEC_PKT_INT 0x02
0274
0275 #define AMR_DSR1_VADDR 0x01
0276 #define AMR_DSR1_EORP 0x02
0277 #define AMR_DSR1_PKT_IP 0x04
0278 #define AMR_DSR1_DECHO_ON 0x08
0279 #define AMR_DSR1_DLOOP_ON 0x10
0280 #define AMR_DSR1_DBACK_OFF 0x20
0281 #define AMR_DSR1_EOTP 0x40
0282 #define AMR_DSR1_CXMT_ABRT 0x80
0283
0284 #define AMR_DSR2_LBRP 0x01
0285 #define AMR_DSR2_RBA 0x02
0286 #define AMR_DSR2_RPLOST 0x04
0287 #define AMR_DSR2_LAST_BYTE 0x08
0288 #define AMR_DSR2_TBE 0x10
0289 #define AMR_DSR2_MARK_IDLE 0x20
0290 #define AMR_DSR2_FLAG_IDLE 0x40
0291 #define AMR_DSR2_SECOND_PKT 0x80
0292
0293 #define AMR_DER_RABRT 0x01
0294 #define AMR_DER_RFRAME 0x02
0295 #define AMR_DER_COLLISION 0x04
0296 #define AMR_DER_FCS 0x08
0297 #define AMR_DER_OVFL 0x10
0298 #define AMR_DER_UNFL 0x20
0299 #define AMR_DER_OVRN 0x40
0300 #define AMR_DER_UNRN 0x80
0301
0302
0303 #define AMR_PP_PPCR1 0xC0
0304 #define AMR_PP_PPSR 0xC1
0305 #define AMR_PP_PPIER 0xC2
0306 #define AMR_PP_MTDR 0xC3
0307 #define AMR_PP_MRDR 0xC3
0308 #define AMR_PP_CITDR0 0xC4
0309 #define AMR_PP_CIRDR0 0xC4
0310 #define AMR_PP_CITDR1 0xC5
0311 #define AMR_PP_CIRDR1 0xC5
0312 #define AMR_PP_PPCR2 0xC8
0313 #define AMR_PP_PPCR3 0xC9
0314
0315 struct snd_amd7930 {
0316 spinlock_t lock;
0317 void __iomem *regs;
0318 u32 flags;
0319 #define AMD7930_FLAG_PLAYBACK 0x00000001
0320 #define AMD7930_FLAG_CAPTURE 0x00000002
0321
0322 struct amd7930_map map;
0323
0324 struct snd_card *card;
0325 struct snd_pcm *pcm;
0326 struct snd_pcm_substream *playback_substream;
0327 struct snd_pcm_substream *capture_substream;
0328
0329
0330 unsigned char *p_orig, *p_cur;
0331 int p_left;
0332 unsigned char *c_orig, *c_cur;
0333 int c_left;
0334
0335 int rgain;
0336 int pgain;
0337 int mgain;
0338
0339 struct platform_device *op;
0340 unsigned int irq;
0341 struct snd_amd7930 *next;
0342 };
0343
0344 static struct snd_amd7930 *amd7930_list;
0345
0346
0347 static __inline__ void amd7930_idle(struct snd_amd7930 *amd)
0348 {
0349 unsigned long flags;
0350
0351 spin_lock_irqsave(&amd->lock, flags);
0352 sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
0353 sbus_writeb(0, amd->regs + AMD7930_DR);
0354 spin_unlock_irqrestore(&amd->lock, flags);
0355 }
0356
0357
0358 static __inline__ void amd7930_enable_ints(struct snd_amd7930 *amd)
0359 {
0360 unsigned long flags;
0361
0362 spin_lock_irqsave(&amd->lock, flags);
0363 sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
0364 sbus_writeb(AM_INIT_ACTIVE, amd->regs + AMD7930_DR);
0365 spin_unlock_irqrestore(&amd->lock, flags);
0366 }
0367
0368
0369 static __inline__ void amd7930_disable_ints(struct snd_amd7930 *amd)
0370 {
0371 unsigned long flags;
0372
0373 spin_lock_irqsave(&amd->lock, flags);
0374 sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
0375 sbus_writeb(AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS, amd->regs + AMD7930_DR);
0376 spin_unlock_irqrestore(&amd->lock, flags);
0377 }
0378
0379
0380
0381
0382 static void __amd7930_write_map(struct snd_amd7930 *amd)
0383 {
0384 struct amd7930_map *map = &amd->map;
0385
0386 sbus_writeb(AMR_MAP_GX, amd->regs + AMD7930_CR);
0387 sbus_writeb(((map->gx >> 0) & 0xff), amd->regs + AMD7930_DR);
0388 sbus_writeb(((map->gx >> 8) & 0xff), amd->regs + AMD7930_DR);
0389
0390 sbus_writeb(AMR_MAP_GR, amd->regs + AMD7930_CR);
0391 sbus_writeb(((map->gr >> 0) & 0xff), amd->regs + AMD7930_DR);
0392 sbus_writeb(((map->gr >> 8) & 0xff), amd->regs + AMD7930_DR);
0393
0394 sbus_writeb(AMR_MAP_STGR, amd->regs + AMD7930_CR);
0395 sbus_writeb(((map->stgr >> 0) & 0xff), amd->regs + AMD7930_DR);
0396 sbus_writeb(((map->stgr >> 8) & 0xff), amd->regs + AMD7930_DR);
0397
0398 sbus_writeb(AMR_MAP_GER, amd->regs + AMD7930_CR);
0399 sbus_writeb(((map->ger >> 0) & 0xff), amd->regs + AMD7930_DR);
0400 sbus_writeb(((map->ger >> 8) & 0xff), amd->regs + AMD7930_DR);
0401
0402 sbus_writeb(AMR_MAP_MMR1, amd->regs + AMD7930_CR);
0403 sbus_writeb(map->mmr1, amd->regs + AMD7930_DR);
0404
0405 sbus_writeb(AMR_MAP_MMR2, amd->regs + AMD7930_CR);
0406 sbus_writeb(map->mmr2, amd->regs + AMD7930_DR);
0407 }
0408
0409
0410
0411
0412
0413
0414 static __const__ __u16 gx_coeff[256] = {
0415 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
0416 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
0417 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
0418 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
0419 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
0420 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
0421 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
0422 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
0423 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
0424 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
0425 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
0426 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
0427 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
0428 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
0429 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
0430 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
0431 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
0432 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
0433 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
0434 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
0435 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
0436 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
0437 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
0438 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
0439 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
0440 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
0441 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
0442 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
0443 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
0444 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
0445 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
0446 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
0447 };
0448
0449 static __const__ __u16 ger_coeff[] = {
0450 0x431f,
0451 0x331f,
0452 0x40dd,
0453 0x11dd,
0454 0x440f,
0455 0x411f,
0456 0x311f,
0457 0x5520,
0458 0x10dd,
0459 0x4211,
0460 0x410f,
0461 0x111f,
0462 0x600b,
0463 0x00dd,
0464 0x4210,
0465 0x110f,
0466 0x7200,
0467 0x2110,
0468 0x2200,
0469 0x000b,
0470 0x000f
0471 };
0472
0473
0474
0475
0476 static void __amd7930_update_map(struct snd_amd7930 *amd)
0477 {
0478 struct amd7930_map *map = &amd->map;
0479 int level;
0480
0481 map->gx = gx_coeff[amd->rgain];
0482 map->stgr = gx_coeff[amd->mgain];
0483 level = (amd->pgain * (256 + ARRAY_SIZE(ger_coeff))) >> 8;
0484 if (level >= 256) {
0485 map->ger = ger_coeff[level - 256];
0486 map->gr = gx_coeff[255];
0487 } else {
0488 map->ger = ger_coeff[0];
0489 map->gr = gx_coeff[level];
0490 }
0491 __amd7930_write_map(amd);
0492 }
0493
0494 static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id)
0495 {
0496 struct snd_amd7930 *amd = dev_id;
0497 unsigned int elapsed;
0498 u8 ir;
0499
0500 spin_lock(&amd->lock);
0501
0502 elapsed = 0;
0503
0504 ir = sbus_readb(amd->regs + AMD7930_IR);
0505 if (ir & AMR_IR_BBUF) {
0506 u8 byte;
0507
0508 if (amd->flags & AMD7930_FLAG_PLAYBACK) {
0509 if (amd->p_left > 0) {
0510 byte = *(amd->p_cur++);
0511 amd->p_left--;
0512 sbus_writeb(byte, amd->regs + AMD7930_BBTB);
0513 if (amd->p_left == 0)
0514 elapsed |= AMD7930_FLAG_PLAYBACK;
0515 } else
0516 sbus_writeb(0, amd->regs + AMD7930_BBTB);
0517 } else if (amd->flags & AMD7930_FLAG_CAPTURE) {
0518 byte = sbus_readb(amd->regs + AMD7930_BBRB);
0519 if (amd->c_left > 0) {
0520 *(amd->c_cur++) = byte;
0521 amd->c_left--;
0522 if (amd->c_left == 0)
0523 elapsed |= AMD7930_FLAG_CAPTURE;
0524 }
0525 }
0526 }
0527 spin_unlock(&amd->lock);
0528
0529 if (elapsed & AMD7930_FLAG_PLAYBACK)
0530 snd_pcm_period_elapsed(amd->playback_substream);
0531 else
0532 snd_pcm_period_elapsed(amd->capture_substream);
0533
0534 return IRQ_HANDLED;
0535 }
0536
0537 static int snd_amd7930_trigger(struct snd_amd7930 *amd, unsigned int flag, int cmd)
0538 {
0539 unsigned long flags;
0540 int result = 0;
0541
0542 spin_lock_irqsave(&amd->lock, flags);
0543 if (cmd == SNDRV_PCM_TRIGGER_START) {
0544 if (!(amd->flags & flag)) {
0545 amd->flags |= flag;
0546
0547
0548 sbus_writeb(AMR_MUX_MCR4, amd->regs + AMD7930_CR);
0549 sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, amd->regs + AMD7930_DR);
0550 }
0551 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
0552 if (amd->flags & flag) {
0553 amd->flags &= ~flag;
0554
0555
0556 sbus_writeb(AMR_MUX_MCR4, amd->regs + AMD7930_CR);
0557 sbus_writeb(0, amd->regs + AMD7930_DR);
0558 }
0559 } else {
0560 result = -EINVAL;
0561 }
0562 spin_unlock_irqrestore(&amd->lock, flags);
0563
0564 return result;
0565 }
0566
0567 static int snd_amd7930_playback_trigger(struct snd_pcm_substream *substream,
0568 int cmd)
0569 {
0570 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0571 return snd_amd7930_trigger(amd, AMD7930_FLAG_PLAYBACK, cmd);
0572 }
0573
0574 static int snd_amd7930_capture_trigger(struct snd_pcm_substream *substream,
0575 int cmd)
0576 {
0577 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0578 return snd_amd7930_trigger(amd, AMD7930_FLAG_CAPTURE, cmd);
0579 }
0580
0581 static int snd_amd7930_playback_prepare(struct snd_pcm_substream *substream)
0582 {
0583 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0584 struct snd_pcm_runtime *runtime = substream->runtime;
0585 unsigned int size = snd_pcm_lib_buffer_bytes(substream);
0586 unsigned long flags;
0587 u8 new_mmr1;
0588
0589 spin_lock_irqsave(&amd->lock, flags);
0590
0591 amd->flags |= AMD7930_FLAG_PLAYBACK;
0592
0593
0594 amd->p_orig = amd->p_cur = runtime->dma_area;
0595 amd->p_left = size;
0596
0597
0598 new_mmr1 = amd->map.mmr1;
0599 if (runtime->format == SNDRV_PCM_FORMAT_A_LAW)
0600 new_mmr1 |= AM_MAP_MMR1_ALAW;
0601 else
0602 new_mmr1 &= ~AM_MAP_MMR1_ALAW;
0603 if (new_mmr1 != amd->map.mmr1) {
0604 amd->map.mmr1 = new_mmr1;
0605 __amd7930_update_map(amd);
0606 }
0607
0608 spin_unlock_irqrestore(&amd->lock, flags);
0609
0610 return 0;
0611 }
0612
0613 static int snd_amd7930_capture_prepare(struct snd_pcm_substream *substream)
0614 {
0615 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0616 struct snd_pcm_runtime *runtime = substream->runtime;
0617 unsigned int size = snd_pcm_lib_buffer_bytes(substream);
0618 unsigned long flags;
0619 u8 new_mmr1;
0620
0621 spin_lock_irqsave(&amd->lock, flags);
0622
0623 amd->flags |= AMD7930_FLAG_CAPTURE;
0624
0625
0626 amd->c_orig = amd->c_cur = runtime->dma_area;
0627 amd->c_left = size;
0628
0629
0630 new_mmr1 = amd->map.mmr1;
0631 if (runtime->format == SNDRV_PCM_FORMAT_A_LAW)
0632 new_mmr1 |= AM_MAP_MMR1_ALAW;
0633 else
0634 new_mmr1 &= ~AM_MAP_MMR1_ALAW;
0635 if (new_mmr1 != amd->map.mmr1) {
0636 amd->map.mmr1 = new_mmr1;
0637 __amd7930_update_map(amd);
0638 }
0639
0640 spin_unlock_irqrestore(&amd->lock, flags);
0641
0642 return 0;
0643 }
0644
0645 static snd_pcm_uframes_t snd_amd7930_playback_pointer(struct snd_pcm_substream *substream)
0646 {
0647 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0648 size_t ptr;
0649
0650 if (!(amd->flags & AMD7930_FLAG_PLAYBACK))
0651 return 0;
0652 ptr = amd->p_cur - amd->p_orig;
0653 return bytes_to_frames(substream->runtime, ptr);
0654 }
0655
0656 static snd_pcm_uframes_t snd_amd7930_capture_pointer(struct snd_pcm_substream *substream)
0657 {
0658 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0659 size_t ptr;
0660
0661 if (!(amd->flags & AMD7930_FLAG_CAPTURE))
0662 return 0;
0663
0664 ptr = amd->c_cur - amd->c_orig;
0665 return bytes_to_frames(substream->runtime, ptr);
0666 }
0667
0668
0669 static const struct snd_pcm_hardware snd_amd7930_pcm_hw =
0670 {
0671 .info = (SNDRV_PCM_INFO_MMAP |
0672 SNDRV_PCM_INFO_MMAP_VALID |
0673 SNDRV_PCM_INFO_INTERLEAVED |
0674 SNDRV_PCM_INFO_BLOCK_TRANSFER |
0675 SNDRV_PCM_INFO_HALF_DUPLEX),
0676 .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
0677 .rates = SNDRV_PCM_RATE_8000,
0678 .rate_min = 8000,
0679 .rate_max = 8000,
0680 .channels_min = 1,
0681 .channels_max = 1,
0682 .buffer_bytes_max = (64*1024),
0683 .period_bytes_min = 1,
0684 .period_bytes_max = (64*1024),
0685 .periods_min = 1,
0686 .periods_max = 1024,
0687 };
0688
0689 static int snd_amd7930_playback_open(struct snd_pcm_substream *substream)
0690 {
0691 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0692 struct snd_pcm_runtime *runtime = substream->runtime;
0693
0694 amd->playback_substream = substream;
0695 runtime->hw = snd_amd7930_pcm_hw;
0696 return 0;
0697 }
0698
0699 static int snd_amd7930_capture_open(struct snd_pcm_substream *substream)
0700 {
0701 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0702 struct snd_pcm_runtime *runtime = substream->runtime;
0703
0704 amd->capture_substream = substream;
0705 runtime->hw = snd_amd7930_pcm_hw;
0706 return 0;
0707 }
0708
0709 static int snd_amd7930_playback_close(struct snd_pcm_substream *substream)
0710 {
0711 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0712
0713 amd->playback_substream = NULL;
0714 return 0;
0715 }
0716
0717 static int snd_amd7930_capture_close(struct snd_pcm_substream *substream)
0718 {
0719 struct snd_amd7930 *amd = snd_pcm_substream_chip(substream);
0720
0721 amd->capture_substream = NULL;
0722 return 0;
0723 }
0724
0725 static const struct snd_pcm_ops snd_amd7930_playback_ops = {
0726 .open = snd_amd7930_playback_open,
0727 .close = snd_amd7930_playback_close,
0728 .prepare = snd_amd7930_playback_prepare,
0729 .trigger = snd_amd7930_playback_trigger,
0730 .pointer = snd_amd7930_playback_pointer,
0731 };
0732
0733 static const struct snd_pcm_ops snd_amd7930_capture_ops = {
0734 .open = snd_amd7930_capture_open,
0735 .close = snd_amd7930_capture_close,
0736 .prepare = snd_amd7930_capture_prepare,
0737 .trigger = snd_amd7930_capture_trigger,
0738 .pointer = snd_amd7930_capture_pointer,
0739 };
0740
0741 static int snd_amd7930_pcm(struct snd_amd7930 *amd)
0742 {
0743 struct snd_pcm *pcm;
0744 int err;
0745
0746 if ((err = snd_pcm_new(amd->card,
0747 "sun_amd7930",
0748 0,
0749 1,
0750 1, &pcm)) < 0)
0751 return err;
0752
0753 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_amd7930_playback_ops);
0754 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_amd7930_capture_ops);
0755
0756 pcm->private_data = amd;
0757 pcm->info_flags = 0;
0758 strcpy(pcm->name, amd->card->shortname);
0759 amd->pcm = pcm;
0760
0761 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
0762 NULL, 64*1024, 64*1024);
0763
0764 return 0;
0765 }
0766
0767 #define VOLUME_MONITOR 0
0768 #define VOLUME_CAPTURE 1
0769 #define VOLUME_PLAYBACK 2
0770
0771 static int snd_amd7930_info_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
0772 {
0773 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0774 uinfo->count = 1;
0775 uinfo->value.integer.min = 0;
0776 uinfo->value.integer.max = 255;
0777
0778 return 0;
0779 }
0780
0781 static int snd_amd7930_get_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
0782 {
0783 struct snd_amd7930 *amd = snd_kcontrol_chip(kctl);
0784 int type = kctl->private_value;
0785 int *swval;
0786
0787 switch (type) {
0788 case VOLUME_MONITOR:
0789 swval = &amd->mgain;
0790 break;
0791 case VOLUME_CAPTURE:
0792 swval = &amd->rgain;
0793 break;
0794 case VOLUME_PLAYBACK:
0795 default:
0796 swval = &amd->pgain;
0797 break;
0798 }
0799
0800 ucontrol->value.integer.value[0] = *swval;
0801
0802 return 0;
0803 }
0804
0805 static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
0806 {
0807 struct snd_amd7930 *amd = snd_kcontrol_chip(kctl);
0808 unsigned long flags;
0809 int type = kctl->private_value;
0810 int *swval, change;
0811
0812 switch (type) {
0813 case VOLUME_MONITOR:
0814 swval = &amd->mgain;
0815 break;
0816 case VOLUME_CAPTURE:
0817 swval = &amd->rgain;
0818 break;
0819 case VOLUME_PLAYBACK:
0820 default:
0821 swval = &amd->pgain;
0822 break;
0823 }
0824
0825 spin_lock_irqsave(&amd->lock, flags);
0826
0827 if (*swval != ucontrol->value.integer.value[0]) {
0828 *swval = ucontrol->value.integer.value[0] & 0xff;
0829 __amd7930_update_map(amd);
0830 change = 1;
0831 } else
0832 change = 0;
0833
0834 spin_unlock_irqrestore(&amd->lock, flags);
0835
0836 return change;
0837 }
0838
0839 static const struct snd_kcontrol_new amd7930_controls[] = {
0840 {
0841 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0842 .name = "Monitor Volume",
0843 .index = 0,
0844 .info = snd_amd7930_info_volume,
0845 .get = snd_amd7930_get_volume,
0846 .put = snd_amd7930_put_volume,
0847 .private_value = VOLUME_MONITOR,
0848 },
0849 {
0850 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0851 .name = "Capture Volume",
0852 .index = 0,
0853 .info = snd_amd7930_info_volume,
0854 .get = snd_amd7930_get_volume,
0855 .put = snd_amd7930_put_volume,
0856 .private_value = VOLUME_CAPTURE,
0857 },
0858 {
0859 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0860 .name = "Playback Volume",
0861 .index = 0,
0862 .info = snd_amd7930_info_volume,
0863 .get = snd_amd7930_get_volume,
0864 .put = snd_amd7930_put_volume,
0865 .private_value = VOLUME_PLAYBACK,
0866 },
0867 };
0868
0869 static int snd_amd7930_mixer(struct snd_amd7930 *amd)
0870 {
0871 struct snd_card *card;
0872 int idx, err;
0873
0874 if (snd_BUG_ON(!amd || !amd->card))
0875 return -EINVAL;
0876
0877 card = amd->card;
0878 strcpy(card->mixername, card->shortname);
0879
0880 for (idx = 0; idx < ARRAY_SIZE(amd7930_controls); idx++) {
0881 if ((err = snd_ctl_add(card,
0882 snd_ctl_new1(&amd7930_controls[idx], amd))) < 0)
0883 return err;
0884 }
0885
0886 return 0;
0887 }
0888
0889 static int snd_amd7930_free(struct snd_amd7930 *amd)
0890 {
0891 struct platform_device *op = amd->op;
0892
0893 amd7930_idle(amd);
0894
0895 if (amd->irq)
0896 free_irq(amd->irq, amd);
0897
0898 if (amd->regs)
0899 of_iounmap(&op->resource[0], amd->regs,
0900 resource_size(&op->resource[0]));
0901
0902 kfree(amd);
0903
0904 return 0;
0905 }
0906
0907 static int snd_amd7930_dev_free(struct snd_device *device)
0908 {
0909 struct snd_amd7930 *amd = device->device_data;
0910
0911 return snd_amd7930_free(amd);
0912 }
0913
0914 static const struct snd_device_ops snd_amd7930_dev_ops = {
0915 .dev_free = snd_amd7930_dev_free,
0916 };
0917
0918 static int snd_amd7930_create(struct snd_card *card,
0919 struct platform_device *op,
0920 int irq, int dev,
0921 struct snd_amd7930 **ramd)
0922 {
0923 struct snd_amd7930 *amd;
0924 unsigned long flags;
0925 int err;
0926
0927 *ramd = NULL;
0928 amd = kzalloc(sizeof(*amd), GFP_KERNEL);
0929 if (amd == NULL)
0930 return -ENOMEM;
0931
0932 spin_lock_init(&amd->lock);
0933 amd->card = card;
0934 amd->op = op;
0935
0936 amd->regs = of_ioremap(&op->resource[0], 0,
0937 resource_size(&op->resource[0]), "amd7930");
0938 if (!amd->regs) {
0939 snd_printk(KERN_ERR
0940 "amd7930-%d: Unable to map chip registers.\n", dev);
0941 kfree(amd);
0942 return -EIO;
0943 }
0944
0945 amd7930_idle(amd);
0946
0947 if (request_irq(irq, snd_amd7930_interrupt,
0948 IRQF_SHARED, "amd7930", amd)) {
0949 snd_printk(KERN_ERR "amd7930-%d: Unable to grab IRQ %d\n",
0950 dev, irq);
0951 snd_amd7930_free(amd);
0952 return -EBUSY;
0953 }
0954 amd->irq = irq;
0955
0956 amd7930_enable_ints(amd);
0957
0958 spin_lock_irqsave(&amd->lock, flags);
0959
0960 amd->rgain = 128;
0961 amd->pgain = 200;
0962 amd->mgain = 0;
0963
0964 memset(&amd->map, 0, sizeof(amd->map));
0965 amd->map.mmr1 = (AM_MAP_MMR1_GX | AM_MAP_MMR1_GER |
0966 AM_MAP_MMR1_GR | AM_MAP_MMR1_STG);
0967 amd->map.mmr2 = (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
0968
0969 __amd7930_update_map(amd);
0970
0971
0972 sbus_writeb(AMR_MUX_MCR1, amd->regs + AMD7930_CR);
0973 sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4),
0974 amd->regs + AMD7930_DR);
0975
0976 spin_unlock_irqrestore(&amd->lock, flags);
0977
0978 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
0979 amd, &snd_amd7930_dev_ops);
0980 if (err < 0) {
0981 snd_amd7930_free(amd);
0982 return err;
0983 }
0984
0985 *ramd = amd;
0986 return 0;
0987 }
0988
0989 static int amd7930_sbus_probe(struct platform_device *op)
0990 {
0991 struct resource *rp = &op->resource[0];
0992 static int dev_num;
0993 struct snd_card *card;
0994 struct snd_amd7930 *amd;
0995 int err, irq;
0996
0997 irq = op->archdata.irqs[0];
0998
0999 if (dev_num >= SNDRV_CARDS)
1000 return -ENODEV;
1001 if (!enable[dev_num]) {
1002 dev_num++;
1003 return -ENOENT;
1004 }
1005
1006 err = snd_card_new(&op->dev, index[dev_num], id[dev_num],
1007 THIS_MODULE, 0, &card);
1008 if (err < 0)
1009 return err;
1010
1011 strcpy(card->driver, "AMD7930");
1012 strcpy(card->shortname, "Sun AMD7930");
1013 sprintf(card->longname, "%s at 0x%02lx:0x%08Lx, irq %d",
1014 card->shortname,
1015 rp->flags & 0xffL,
1016 (unsigned long long)rp->start,
1017 irq);
1018
1019 if ((err = snd_amd7930_create(card, op,
1020 irq, dev_num, &amd)) < 0)
1021 goto out_err;
1022
1023 err = snd_amd7930_pcm(amd);
1024 if (err < 0)
1025 goto out_err;
1026
1027 err = snd_amd7930_mixer(amd);
1028 if (err < 0)
1029 goto out_err;
1030
1031 err = snd_card_register(card);
1032 if (err < 0)
1033 goto out_err;
1034
1035 amd->next = amd7930_list;
1036 amd7930_list = amd;
1037
1038 dev_num++;
1039
1040 return 0;
1041
1042 out_err:
1043 snd_card_free(card);
1044 return err;
1045 }
1046
1047 static const struct of_device_id amd7930_match[] = {
1048 {
1049 .name = "audio",
1050 },
1051 {},
1052 };
1053 MODULE_DEVICE_TABLE(of, amd7930_match);
1054
1055 static struct platform_driver amd7930_sbus_driver = {
1056 .driver = {
1057 .name = "audio",
1058 .of_match_table = amd7930_match,
1059 },
1060 .probe = amd7930_sbus_probe,
1061 };
1062
1063 static int __init amd7930_init(void)
1064 {
1065 return platform_driver_register(&amd7930_sbus_driver);
1066 }
1067
1068 static void __exit amd7930_exit(void)
1069 {
1070 struct snd_amd7930 *p = amd7930_list;
1071
1072 while (p != NULL) {
1073 struct snd_amd7930 *next = p->next;
1074
1075 snd_card_free(p->card);
1076
1077 p = next;
1078 }
1079
1080 amd7930_list = NULL;
1081
1082 platform_driver_unregister(&amd7930_sbus_driver);
1083 }
1084
1085 module_init(amd7930_init);
1086 module_exit(amd7930_exit);