177f5075aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
202bec490STim Blechmann /* -*- linux-c -*- *
302bec490STim Blechmann *
402bec490STim Blechmann * ALSA driver for the digigram lx6464es interface
502bec490STim Blechmann * low-level interface
602bec490STim Blechmann *
702bec490STim Blechmann * Copyright (c) 2009 Tim Blechmann <tim@klingt.org>
802bec490STim Blechmann */
902bec490STim Blechmann
1002bec490STim Blechmann /* #define RMH_DEBUG 1 */
1102bec490STim Blechmann
12c546ca95SMaxime Ripard #include <linux/bitops.h>
1302bec490STim Blechmann #include <linux/module.h>
1402bec490STim Blechmann #include <linux/pci.h>
1502bec490STim Blechmann #include <linux/delay.h>
1602bec490STim Blechmann
1702bec490STim Blechmann #include "lx6464es.h"
1802bec490STim Blechmann #include "lx_core.h"
1902bec490STim Blechmann
2002bec490STim Blechmann /* low-level register access */
2102bec490STim Blechmann
2202bec490STim Blechmann static const unsigned long dsp_port_offsets[] = {
2302bec490STim Blechmann 0,
2402bec490STim Blechmann 0x400,
2502bec490STim Blechmann 0x401,
2602bec490STim Blechmann 0x402,
2702bec490STim Blechmann 0x403,
2802bec490STim Blechmann 0x404,
2902bec490STim Blechmann 0x405,
3002bec490STim Blechmann 0x406,
3102bec490STim Blechmann 0x407,
3202bec490STim Blechmann 0x408,
3302bec490STim Blechmann 0x409,
3402bec490STim Blechmann 0x40a,
3502bec490STim Blechmann 0x40b,
3602bec490STim Blechmann 0x40c,
3702bec490STim Blechmann
3802bec490STim Blechmann 0x410,
3902bec490STim Blechmann 0x411,
4002bec490STim Blechmann 0x412,
4102bec490STim Blechmann 0x413,
4202bec490STim Blechmann 0x414,
4302bec490STim Blechmann 0x415,
4402bec490STim Blechmann 0x416,
4502bec490STim Blechmann
4602bec490STim Blechmann 0x420,
4702bec490STim Blechmann 0x430,
4802bec490STim Blechmann 0x431,
4902bec490STim Blechmann 0x432,
5002bec490STim Blechmann 0x433,
5102bec490STim Blechmann 0x434,
5202bec490STim Blechmann 0x440
5302bec490STim Blechmann };
5402bec490STim Blechmann
lx_dsp_register(struct lx6464es * chip,int port)5502bec490STim Blechmann static void __iomem *lx_dsp_register(struct lx6464es *chip, int port)
5602bec490STim Blechmann {
5702bec490STim Blechmann void __iomem *base_address = chip->port_dsp_bar;
5802bec490STim Blechmann return base_address + dsp_port_offsets[port]*4;
5902bec490STim Blechmann }
6002bec490STim Blechmann
lx_dsp_reg_read(struct lx6464es * chip,int port)6102bec490STim Blechmann unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port)
6202bec490STim Blechmann {
6302bec490STim Blechmann void __iomem *address = lx_dsp_register(chip, port);
6402bec490STim Blechmann return ioread32(address);
6502bec490STim Blechmann }
6602bec490STim Blechmann
lx_dsp_reg_readbuf(struct lx6464es * chip,int port,u32 * data,u32 len)67afd00d72STim Blechmann static void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data,
68afd00d72STim Blechmann u32 len)
6902bec490STim Blechmann {
70a2987855STim Blechmann u32 __iomem *address = lx_dsp_register(chip, port);
71a2987855STim Blechmann int i;
72a2987855STim Blechmann
73a2987855STim Blechmann /* we cannot use memcpy_fromio */
74a2987855STim Blechmann for (i = 0; i != len; ++i)
75a2987855STim Blechmann data[i] = ioread32(address + i);
7602bec490STim Blechmann }
7702bec490STim Blechmann
7802bec490STim Blechmann
lx_dsp_reg_write(struct lx6464es * chip,int port,unsigned data)7902bec490STim Blechmann void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data)
8002bec490STim Blechmann {
8102bec490STim Blechmann void __iomem *address = lx_dsp_register(chip, port);
8202bec490STim Blechmann iowrite32(data, address);
8302bec490STim Blechmann }
8402bec490STim Blechmann
lx_dsp_reg_writebuf(struct lx6464es * chip,int port,const u32 * data,u32 len)85afd00d72STim Blechmann static void lx_dsp_reg_writebuf(struct lx6464es *chip, int port,
86afd00d72STim Blechmann const u32 *data, u32 len)
8702bec490STim Blechmann {
88a2987855STim Blechmann u32 __iomem *address = lx_dsp_register(chip, port);
89a2987855STim Blechmann int i;
90a2987855STim Blechmann
91a2987855STim Blechmann /* we cannot use memcpy_to */
92a2987855STim Blechmann for (i = 0; i != len; ++i)
93a2987855STim Blechmann iowrite32(data[i], address + i);
9402bec490STim Blechmann }
9502bec490STim Blechmann
9602bec490STim Blechmann
9702bec490STim Blechmann static const unsigned long plx_port_offsets[] = {
9802bec490STim Blechmann 0x04,
9902bec490STim Blechmann 0x40,
10002bec490STim Blechmann 0x44,
10102bec490STim Blechmann 0x48,
10202bec490STim Blechmann 0x4c,
10302bec490STim Blechmann 0x50,
10402bec490STim Blechmann 0x54,
10502bec490STim Blechmann 0x58,
10602bec490STim Blechmann 0x5c,
10702bec490STim Blechmann 0x64,
10802bec490STim Blechmann 0x68,
10902bec490STim Blechmann 0x6C
11002bec490STim Blechmann };
11102bec490STim Blechmann
lx_plx_register(struct lx6464es * chip,int port)11202bec490STim Blechmann static void __iomem *lx_plx_register(struct lx6464es *chip, int port)
11302bec490STim Blechmann {
11402bec490STim Blechmann void __iomem *base_address = chip->port_plx_remapped;
11502bec490STim Blechmann return base_address + plx_port_offsets[port];
11602bec490STim Blechmann }
11702bec490STim Blechmann
lx_plx_reg_read(struct lx6464es * chip,int port)11802bec490STim Blechmann unsigned long lx_plx_reg_read(struct lx6464es *chip, int port)
11902bec490STim Blechmann {
12002bec490STim Blechmann void __iomem *address = lx_plx_register(chip, port);
12102bec490STim Blechmann return ioread32(address);
12202bec490STim Blechmann }
12302bec490STim Blechmann
lx_plx_reg_write(struct lx6464es * chip,int port,u32 data)12402bec490STim Blechmann void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data)
12502bec490STim Blechmann {
12602bec490STim Blechmann void __iomem *address = lx_plx_register(chip, port);
12702bec490STim Blechmann iowrite32(data, address);
12802bec490STim Blechmann }
12902bec490STim Blechmann
13002bec490STim Blechmann /* rmh */
13102bec490STim Blechmann
13202bec490STim Blechmann #ifdef CONFIG_SND_DEBUG
13302bec490STim Blechmann #define CMD_NAME(a) a
13402bec490STim Blechmann #else
13502bec490STim Blechmann #define CMD_NAME(a) NULL
13602bec490STim Blechmann #endif
13702bec490STim Blechmann
13802bec490STim Blechmann #define Reg_CSM_MR 0x00000002
13902bec490STim Blechmann #define Reg_CSM_MC 0x00000001
14002bec490STim Blechmann
14102bec490STim Blechmann struct dsp_cmd_info {
14202bec490STim Blechmann u32 dcCodeOp; /* Op Code of the command (usually 1st 24-bits
14302bec490STim Blechmann * word).*/
14402bec490STim Blechmann u16 dcCmdLength; /* Command length in words of 24 bits.*/
14502bec490STim Blechmann u16 dcStatusType; /* Status type: 0 for fixed length, 1 for
14602bec490STim Blechmann * random. */
14702bec490STim Blechmann u16 dcStatusLength; /* Status length (if fixed).*/
14802bec490STim Blechmann char *dcOpName;
14902bec490STim Blechmann };
15002bec490STim Blechmann
15102bec490STim Blechmann /*
15202bec490STim Blechmann Initialization and control data for the Microblaze interface
15302bec490STim Blechmann - OpCode:
15402bec490STim Blechmann the opcode field of the command set at the proper offset
15502bec490STim Blechmann - CmdLength
15602bec490STim Blechmann the number of command words
15702bec490STim Blechmann - StatusType
15802bec490STim Blechmann offset in the status registers: 0 means that the return value may be
15902bec490STim Blechmann different from 0, and must be read
16002bec490STim Blechmann - StatusLength
16102bec490STim Blechmann the number of status words (in addition to the return value)
16202bec490STim Blechmann */
16302bec490STim Blechmann
1642f200ce2STakashi Iwai static const struct dsp_cmd_info dsp_commands[] =
16502bec490STim Blechmann {
16602bec490STim Blechmann { (CMD_00_INFO_DEBUG << OPCODE_OFFSET) , 1 /*custom*/
16702bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("INFO_DEBUG") },
16802bec490STim Blechmann { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) , 1 /**/
16902bec490STim Blechmann , 1 , 2 /**/ , CMD_NAME("GET_SYS_CFG") },
17002bec490STim Blechmann { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET) , 1 /**/
17102bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("SET_GRANULARITY") },
17202bec490STim Blechmann { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET) , 1 /**/
17302bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("SET_TIMER_IRQ") },
17402bec490STim Blechmann { (CMD_04_GET_EVENT << OPCODE_OFFSET) , 1 /**/
17502bec490STim Blechmann , 1 , 0 /*up to 10*/ , CMD_NAME("GET_EVENT") },
17602bec490STim Blechmann { (CMD_05_GET_PIPES << OPCODE_OFFSET) , 1 /**/
17702bec490STim Blechmann , 1 , 2 /*up to 4*/ , CMD_NAME("GET_PIPES") },
17802bec490STim Blechmann { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET) , 1 /**/
17902bec490STim Blechmann , 0 , 0 /**/ , CMD_NAME("ALLOCATE_PIPE") },
18002bec490STim Blechmann { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET) , 1 /**/
18102bec490STim Blechmann , 0 , 0 /**/ , CMD_NAME("RELEASE_PIPE") },
18202bec490STim Blechmann { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) , 1 /**/
18302bec490STim Blechmann , 1 , MAX_STREAM_BUFFER , CMD_NAME("ASK_BUFFERS") },
18402bec490STim Blechmann { (CMD_09_STOP_PIPE << OPCODE_OFFSET) , 1 /**/
18502bec490STim Blechmann , 0 , 0 /*up to 2*/ , CMD_NAME("STOP_PIPE") },
18602bec490STim Blechmann { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET) , 1 /**/
18702bec490STim Blechmann , 1 , 1 /*up to 2*/ , CMD_NAME("GET_PIPE_SPL_COUNT") },
18802bec490STim Blechmann { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET) , 1 /*up to 5*/
18902bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("TOGGLE_PIPE_STATE") },
19002bec490STim Blechmann { (CMD_0C_DEF_STREAM << OPCODE_OFFSET) , 1 /*up to 4*/
19102bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("DEF_STREAM") },
19202bec490STim Blechmann { (CMD_0D_SET_MUTE << OPCODE_OFFSET) , 3 /**/
19302bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("SET_MUTE") },
19402bec490STim Blechmann { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET) , 1/**/
19502bec490STim Blechmann , 1 , 2 /**/ , CMD_NAME("GET_STREAM_SPL_COUNT") },
19602bec490STim Blechmann { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET) , 3 /*up to 4*/
19702bec490STim Blechmann , 0 , 1 /**/ , CMD_NAME("UPDATE_BUFFER") },
19802bec490STim Blechmann { (CMD_10_GET_BUFFER << OPCODE_OFFSET) , 1 /**/
19902bec490STim Blechmann , 1 , 4 /**/ , CMD_NAME("GET_BUFFER") },
20002bec490STim Blechmann { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET) , 1 /**/
20102bec490STim Blechmann , 1 , 1 /*up to 4*/ , CMD_NAME("CANCEL_BUFFER") },
20202bec490STim Blechmann { (CMD_12_GET_PEAK << OPCODE_OFFSET) , 1 /**/
20302bec490STim Blechmann , 1 , 1 /**/ , CMD_NAME("GET_PEAK") },
20402bec490STim Blechmann { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET) , 1 /**/
20502bec490STim Blechmann , 1 , 0 /**/ , CMD_NAME("SET_STREAM_STATE") },
20602bec490STim Blechmann };
20702bec490STim Blechmann
lx_message_init(struct lx_rmh * rmh,enum cmd_mb_opcodes cmd)20802bec490STim Blechmann static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd)
20902bec490STim Blechmann {
21002bec490STim Blechmann snd_BUG_ON(cmd >= CMD_14_INVALID);
21102bec490STim Blechmann
21202bec490STim Blechmann rmh->cmd[0] = dsp_commands[cmd].dcCodeOp;
21302bec490STim Blechmann rmh->cmd_len = dsp_commands[cmd].dcCmdLength;
21402bec490STim Blechmann rmh->stat_len = dsp_commands[cmd].dcStatusLength;
21502bec490STim Blechmann rmh->dsp_stat = dsp_commands[cmd].dcStatusType;
21602bec490STim Blechmann rmh->cmd_idx = cmd;
21702bec490STim Blechmann memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32));
21802bec490STim Blechmann
21902bec490STim Blechmann #ifdef CONFIG_SND_DEBUG
22002bec490STim Blechmann memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32));
22102bec490STim Blechmann #endif
22202bec490STim Blechmann #ifdef RMH_DEBUG
22302bec490STim Blechmann rmh->cmd_idx = cmd;
22402bec490STim Blechmann #endif
22502bec490STim Blechmann }
22602bec490STim Blechmann
22702bec490STim Blechmann #ifdef RMH_DEBUG
22802bec490STim Blechmann #define LXRMH "lx6464es rmh: "
lx_message_dump(struct lx_rmh * rmh)22902bec490STim Blechmann static void lx_message_dump(struct lx_rmh *rmh)
23002bec490STim Blechmann {
23102bec490STim Blechmann u8 idx = rmh->cmd_idx;
23202bec490STim Blechmann int i;
23302bec490STim Blechmann
23402bec490STim Blechmann snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName);
23502bec490STim Blechmann
23602bec490STim Blechmann for (i = 0; i != rmh->cmd_len; ++i)
23702bec490STim Blechmann snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]);
23802bec490STim Blechmann
23902bec490STim Blechmann for (i = 0; i != rmh->stat_len; ++i)
24002bec490STim Blechmann snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]);
24102bec490STim Blechmann snd_printk("\n");
24202bec490STim Blechmann }
24302bec490STim Blechmann #else
lx_message_dump(struct lx_rmh * rmh)24402bec490STim Blechmann static inline void lx_message_dump(struct lx_rmh *rmh)
24502bec490STim Blechmann {}
24602bec490STim Blechmann #endif
24702bec490STim Blechmann
24802bec490STim Blechmann
24902bec490STim Blechmann
25002bec490STim Blechmann /* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */
25102bec490STim Blechmann #define XILINX_TIMEOUT_MS 40
25202bec490STim Blechmann #define XILINX_POLL_NO_SLEEP 100
25302bec490STim Blechmann #define XILINX_POLL_ITERATIONS 150
25402bec490STim Blechmann
25502bec490STim Blechmann
lx_message_send_atomic(struct lx6464es * chip,struct lx_rmh * rmh)25602bec490STim Blechmann static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
25702bec490STim Blechmann {
25802bec490STim Blechmann u32 reg = ED_DSP_TIMED_OUT;
25902bec490STim Blechmann int dwloop;
26002bec490STim Blechmann
26102bec490STim Blechmann if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
262be4e6d3cSTakashi Iwai dev_err(chip->card->dev, "PIOSendMessage eReg_CSM %x\n", reg);
26302bec490STim Blechmann return -EBUSY;
26402bec490STim Blechmann }
26502bec490STim Blechmann
26602bec490STim Blechmann /* write command */
26702bec490STim Blechmann lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len);
26802bec490STim Blechmann
26902bec490STim Blechmann /* MicoBlaze gogogo */
27002bec490STim Blechmann lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC);
27102bec490STim Blechmann
27295eff499STim Blechmann /* wait for device to answer */
27302bec490STim Blechmann for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) {
27402bec490STim Blechmann if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) {
27502bec490STim Blechmann if (rmh->dsp_stat == 0)
27602bec490STim Blechmann reg = lx_dsp_reg_read(chip, eReg_CRM1);
27702bec490STim Blechmann else
27802bec490STim Blechmann reg = 0;
27902bec490STim Blechmann goto polling_successful;
28002bec490STim Blechmann } else
28102bec490STim Blechmann udelay(1);
28202bec490STim Blechmann }
283be4e6d3cSTakashi Iwai dev_warn(chip->card->dev, "TIMEOUT lx_message_send_atomic! "
28402bec490STim Blechmann "polling failed\n");
28502bec490STim Blechmann
28602bec490STim Blechmann polling_successful:
28702bec490STim Blechmann if ((reg & ERROR_VALUE) == 0) {
28802bec490STim Blechmann /* read response */
28902bec490STim Blechmann if (rmh->stat_len) {
29002bec490STim Blechmann snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1));
29102bec490STim Blechmann lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat,
29202bec490STim Blechmann rmh->stat_len);
29302bec490STim Blechmann }
29402bec490STim Blechmann } else
295be4e6d3cSTakashi Iwai dev_err(chip->card->dev, "rmh error: %08x\n", reg);
29602bec490STim Blechmann
29702bec490STim Blechmann /* clear Reg_CSM_MR */
29802bec490STim Blechmann lx_dsp_reg_write(chip, eReg_CSM, 0);
29902bec490STim Blechmann
30002bec490STim Blechmann switch (reg) {
30102bec490STim Blechmann case ED_DSP_TIMED_OUT:
302be4e6d3cSTakashi Iwai dev_warn(chip->card->dev, "lx_message_send: dsp timeout\n");
30302bec490STim Blechmann return -ETIMEDOUT;
30402bec490STim Blechmann
30502bec490STim Blechmann case ED_DSP_CRASHED:
306be4e6d3cSTakashi Iwai dev_warn(chip->card->dev, "lx_message_send: dsp crashed\n");
30702bec490STim Blechmann return -EAGAIN;
30802bec490STim Blechmann }
30902bec490STim Blechmann
31002bec490STim Blechmann lx_message_dump(rmh);
31102bec490STim Blechmann
31202bec490STim Blechmann return reg;
31302bec490STim Blechmann }
31402bec490STim Blechmann
31502bec490STim Blechmann
31602bec490STim Blechmann /* low-level dsp access */
lx_dsp_get_version(struct lx6464es * chip,u32 * rdsp_version)317e23e7a14SBill Pemberton int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version)
31802bec490STim Blechmann {
31902bec490STim Blechmann u16 ret;
32002bec490STim Blechmann
3216336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
32202bec490STim Blechmann
32302bec490STim Blechmann lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
32402bec490STim Blechmann ret = lx_message_send_atomic(chip, &chip->rmh);
32502bec490STim Blechmann
32602bec490STim Blechmann *rdsp_version = chip->rmh.stat[1];
3276336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
32802bec490STim Blechmann return ret;
32902bec490STim Blechmann }
33002bec490STim Blechmann
lx_dsp_get_clock_frequency(struct lx6464es * chip,u32 * rfreq)33102bec490STim Blechmann int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
33202bec490STim Blechmann {
33302bec490STim Blechmann u16 ret = 0;
33402bec490STim Blechmann u32 freq_raw = 0;
33502bec490STim Blechmann u32 freq = 0;
33602bec490STim Blechmann u32 frequency = 0;
33702bec490STim Blechmann
3386336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
33902bec490STim Blechmann
34002bec490STim Blechmann lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
34102bec490STim Blechmann ret = lx_message_send_atomic(chip, &chip->rmh);
34202bec490STim Blechmann
34302bec490STim Blechmann if (ret == 0) {
34402bec490STim Blechmann freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET;
34502bec490STim Blechmann freq = freq_raw & XES_FREQ_COUNT8_MASK;
34602bec490STim Blechmann
34702bec490STim Blechmann if ((freq < XES_FREQ_COUNT8_48_MAX) ||
34802bec490STim Blechmann (freq > XES_FREQ_COUNT8_44_MIN))
34902bec490STim Blechmann frequency = 0; /* unknown */
35002bec490STim Blechmann else if (freq >= XES_FREQ_COUNT8_44_MAX)
35102bec490STim Blechmann frequency = 44100;
35202bec490STim Blechmann else
35302bec490STim Blechmann frequency = 48000;
35402bec490STim Blechmann }
35502bec490STim Blechmann
3566336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
35702bec490STim Blechmann
35802bec490STim Blechmann *rfreq = frequency * chip->freq_ratio;
35902bec490STim Blechmann
36002bec490STim Blechmann return ret;
36102bec490STim Blechmann }
36202bec490STim Blechmann
lx_dsp_get_mac(struct lx6464es * chip)36380b52490STim Blechmann int lx_dsp_get_mac(struct lx6464es *chip)
36402bec490STim Blechmann {
36502bec490STim Blechmann u32 macmsb, maclsb;
36602bec490STim Blechmann
36702bec490STim Blechmann macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF;
36802bec490STim Blechmann maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF;
36902bec490STim Blechmann
37002bec490STim Blechmann /* todo: endianess handling */
37180b52490STim Blechmann chip->mac_address[5] = ((u8 *)(&maclsb))[0];
37280b52490STim Blechmann chip->mac_address[4] = ((u8 *)(&maclsb))[1];
37380b52490STim Blechmann chip->mac_address[3] = ((u8 *)(&maclsb))[2];
37480b52490STim Blechmann chip->mac_address[2] = ((u8 *)(&macmsb))[0];
37580b52490STim Blechmann chip->mac_address[1] = ((u8 *)(&macmsb))[1];
37680b52490STim Blechmann chip->mac_address[0] = ((u8 *)(&macmsb))[2];
37702bec490STim Blechmann
37802bec490STim Blechmann return 0;
37902bec490STim Blechmann }
38002bec490STim Blechmann
38102bec490STim Blechmann
lx_dsp_set_granularity(struct lx6464es * chip,u32 gran)38202bec490STim Blechmann int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran)
38302bec490STim Blechmann {
38402bec490STim Blechmann int ret;
38502bec490STim Blechmann
3866336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
38702bec490STim Blechmann
38802bec490STim Blechmann lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY);
38902bec490STim Blechmann chip->rmh.cmd[0] |= gran;
39002bec490STim Blechmann
39102bec490STim Blechmann ret = lx_message_send_atomic(chip, &chip->rmh);
3926336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
39302bec490STim Blechmann return ret;
39402bec490STim Blechmann }
39502bec490STim Blechmann
lx_dsp_read_async_events(struct lx6464es * chip,u32 * data)39602bec490STim Blechmann int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
39702bec490STim Blechmann {
39802bec490STim Blechmann int ret;
39902bec490STim Blechmann
4006336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
40102bec490STim Blechmann
40202bec490STim Blechmann lx_message_init(&chip->rmh, CMD_04_GET_EVENT);
40302bec490STim Blechmann chip->rmh.stat_len = 9; /* we don't necessarily need the full length */
40402bec490STim Blechmann
40502bec490STim Blechmann ret = lx_message_send_atomic(chip, &chip->rmh);
40602bec490STim Blechmann
40702bec490STim Blechmann if (!ret)
40802bec490STim Blechmann memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32));
40902bec490STim Blechmann
4106336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
41102bec490STim Blechmann return ret;
41202bec490STim Blechmann }
41302bec490STim Blechmann
41402bec490STim Blechmann #define PIPE_INFO_TO_CMD(capture, pipe) \
41502bec490STim Blechmann ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
41602bec490STim Blechmann
41702bec490STim Blechmann
41802bec490STim Blechmann
41902bec490STim Blechmann /* low-level pipe handling */
lx_pipe_allocate(struct lx6464es * chip,u32 pipe,int is_capture,int channels)42002bec490STim Blechmann int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
42102bec490STim Blechmann int channels)
42202bec490STim Blechmann {
42302bec490STim Blechmann int err;
42402bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
42502bec490STim Blechmann
4266336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
42702bec490STim Blechmann lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE);
42802bec490STim Blechmann
42902bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
43002bec490STim Blechmann chip->rmh.cmd[0] |= channels;
43102bec490STim Blechmann
43202bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
4336336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
43402bec490STim Blechmann
43502bec490STim Blechmann if (err != 0)
436be4e6d3cSTakashi Iwai dev_err(chip->card->dev, "could not allocate pipe\n");
43702bec490STim Blechmann
43802bec490STim Blechmann return err;
43902bec490STim Blechmann }
44002bec490STim Blechmann
lx_pipe_release(struct lx6464es * chip,u32 pipe,int is_capture)44102bec490STim Blechmann int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture)
44202bec490STim Blechmann {
44302bec490STim Blechmann int err;
44402bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
44502bec490STim Blechmann
4466336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
44702bec490STim Blechmann lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE);
44802bec490STim Blechmann
44902bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
45002bec490STim Blechmann
45102bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
4526336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
45302bec490STim Blechmann
45402bec490STim Blechmann return err;
45502bec490STim Blechmann }
45602bec490STim Blechmann
lx_buffer_ask(struct lx6464es * chip,u32 pipe,int is_capture,u32 * r_needed,u32 * r_freed,u32 * size_array)45702bec490STim Blechmann int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
45802bec490STim Blechmann u32 *r_needed, u32 *r_freed, u32 *size_array)
45902bec490STim Blechmann {
46002bec490STim Blechmann int err;
46102bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
46202bec490STim Blechmann
46302bec490STim Blechmann #ifdef CONFIG_SND_DEBUG
46402bec490STim Blechmann if (size_array)
46502bec490STim Blechmann memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER);
46602bec490STim Blechmann #endif
46702bec490STim Blechmann
46802bec490STim Blechmann *r_needed = 0;
46902bec490STim Blechmann *r_freed = 0;
47002bec490STim Blechmann
4716336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
47202bec490STim Blechmann lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS);
47302bec490STim Blechmann
47402bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
47502bec490STim Blechmann
47602bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
47702bec490STim Blechmann
47802bec490STim Blechmann if (!err) {
47902bec490STim Blechmann int i;
48002bec490STim Blechmann for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
48102bec490STim Blechmann u32 stat = chip->rmh.stat[i];
48202bec490STim Blechmann if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) {
48302bec490STim Blechmann /* finished */
48402bec490STim Blechmann *r_freed += 1;
48502bec490STim Blechmann if (size_array)
48602bec490STim Blechmann size_array[i] = stat & MASK_DATA_SIZE;
48702bec490STim Blechmann } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET))
48802bec490STim Blechmann == 0)
48902bec490STim Blechmann /* free */
49002bec490STim Blechmann *r_needed += 1;
49102bec490STim Blechmann }
49202bec490STim Blechmann
493be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev,
494be4e6d3cSTakashi Iwai "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
49502bec490STim Blechmann *r_needed, *r_freed);
496*5dac9f8dSDan Carpenter for (i = 0; i < MAX_STREAM_BUFFER && i < chip->rmh.stat_len;
497*5dac9f8dSDan Carpenter ++i) {
498*5dac9f8dSDan Carpenter dev_dbg(chip->card->dev, " stat[%d]: %x, %x\n", i,
49902bec490STim Blechmann chip->rmh.stat[i],
50002bec490STim Blechmann chip->rmh.stat[i] & MASK_DATA_SIZE);
50102bec490STim Blechmann }
50202bec490STim Blechmann }
50302bec490STim Blechmann
5046336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
50502bec490STim Blechmann return err;
50602bec490STim Blechmann }
50702bec490STim Blechmann
50802bec490STim Blechmann
lx_pipe_stop(struct lx6464es * chip,u32 pipe,int is_capture)50902bec490STim Blechmann int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture)
51002bec490STim Blechmann {
51102bec490STim Blechmann int err;
51202bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
51302bec490STim Blechmann
5146336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
51502bec490STim Blechmann lx_message_init(&chip->rmh, CMD_09_STOP_PIPE);
51602bec490STim Blechmann
51702bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
51802bec490STim Blechmann
51902bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
52002bec490STim Blechmann
5216336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
52202bec490STim Blechmann return err;
52302bec490STim Blechmann }
52402bec490STim Blechmann
lx_pipe_toggle_state(struct lx6464es * chip,u32 pipe,int is_capture)52502bec490STim Blechmann static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture)
52602bec490STim Blechmann {
52702bec490STim Blechmann int err;
52802bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
52902bec490STim Blechmann
5306336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
53102bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE);
53202bec490STim Blechmann
53302bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
53402bec490STim Blechmann
53502bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
53602bec490STim Blechmann
5376336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
53802bec490STim Blechmann return err;
53902bec490STim Blechmann }
54002bec490STim Blechmann
54102bec490STim Blechmann
lx_pipe_start(struct lx6464es * chip,u32 pipe,int is_capture)54202bec490STim Blechmann int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture)
54302bec490STim Blechmann {
54402bec490STim Blechmann int err;
54502bec490STim Blechmann
54602bec490STim Blechmann err = lx_pipe_wait_for_idle(chip, pipe, is_capture);
54702bec490STim Blechmann if (err < 0)
54802bec490STim Blechmann return err;
54902bec490STim Blechmann
55002bec490STim Blechmann err = lx_pipe_toggle_state(chip, pipe, is_capture);
55102bec490STim Blechmann
55202bec490STim Blechmann return err;
55302bec490STim Blechmann }
55402bec490STim Blechmann
lx_pipe_pause(struct lx6464es * chip,u32 pipe,int is_capture)55502bec490STim Blechmann int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture)
55602bec490STim Blechmann {
55702bec490STim Blechmann int err = 0;
55802bec490STim Blechmann
55902bec490STim Blechmann err = lx_pipe_wait_for_start(chip, pipe, is_capture);
56002bec490STim Blechmann if (err < 0)
56102bec490STim Blechmann return err;
56202bec490STim Blechmann
56302bec490STim Blechmann err = lx_pipe_toggle_state(chip, pipe, is_capture);
56402bec490STim Blechmann
56502bec490STim Blechmann return err;
56602bec490STim Blechmann }
56702bec490STim Blechmann
56802bec490STim Blechmann
lx_pipe_sample_count(struct lx6464es * chip,u32 pipe,int is_capture,u64 * rsample_count)56902bec490STim Blechmann int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
57002bec490STim Blechmann u64 *rsample_count)
57102bec490STim Blechmann {
57202bec490STim Blechmann int err;
57302bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
57402bec490STim Blechmann
5756336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
57602bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
57702bec490STim Blechmann
57802bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
57902bec490STim Blechmann chip->rmh.stat_len = 2; /* need all words here! */
58002bec490STim Blechmann
58102bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */
58202bec490STim Blechmann
58302bec490STim Blechmann if (err != 0)
584be4e6d3cSTakashi Iwai dev_err(chip->card->dev,
585be4e6d3cSTakashi Iwai "could not query pipe's sample count\n");
58602bec490STim Blechmann else {
58702bec490STim Blechmann *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
58802bec490STim Blechmann << 24) /* hi part */
58902bec490STim Blechmann + chip->rmh.stat[1]; /* lo part */
59002bec490STim Blechmann }
59102bec490STim Blechmann
5926336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
59302bec490STim Blechmann return err;
59402bec490STim Blechmann }
59502bec490STim Blechmann
lx_pipe_state(struct lx6464es * chip,u32 pipe,int is_capture,u16 * rstate)59602bec490STim Blechmann int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
59702bec490STim Blechmann {
59802bec490STim Blechmann int err;
59902bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
60002bec490STim Blechmann
6016336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
60202bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
60302bec490STim Blechmann
60402bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
60502bec490STim Blechmann
60602bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
60702bec490STim Blechmann
60802bec490STim Blechmann if (err != 0)
609be4e6d3cSTakashi Iwai dev_err(chip->card->dev, "could not query pipe's state\n");
61002bec490STim Blechmann else
61102bec490STim Blechmann *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
61202bec490STim Blechmann
6136336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
61402bec490STim Blechmann return err;
61502bec490STim Blechmann }
61602bec490STim Blechmann
lx_pipe_wait_for_state(struct lx6464es * chip,u32 pipe,int is_capture,u16 state)61702bec490STim Blechmann static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe,
61802bec490STim Blechmann int is_capture, u16 state)
61902bec490STim Blechmann {
62002bec490STim Blechmann int i;
62102bec490STim Blechmann
62202bec490STim Blechmann /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms:
62302bec490STim Blechmann * timeout 50 ms */
62402bec490STim Blechmann for (i = 0; i != 50; ++i) {
62502bec490STim Blechmann u16 current_state;
62602bec490STim Blechmann int err = lx_pipe_state(chip, pipe, is_capture, ¤t_state);
62702bec490STim Blechmann
62802bec490STim Blechmann if (err < 0)
62902bec490STim Blechmann return err;
63002bec490STim Blechmann
631a19c921fSTakashi Iwai if (!err && current_state == state)
63202bec490STim Blechmann return 0;
63302bec490STim Blechmann
63402bec490STim Blechmann mdelay(1);
63502bec490STim Blechmann }
63602bec490STim Blechmann
63702bec490STim Blechmann return -ETIMEDOUT;
63802bec490STim Blechmann }
63902bec490STim Blechmann
lx_pipe_wait_for_start(struct lx6464es * chip,u32 pipe,int is_capture)64002bec490STim Blechmann int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture)
64102bec490STim Blechmann {
64202bec490STim Blechmann return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN);
64302bec490STim Blechmann }
64402bec490STim Blechmann
lx_pipe_wait_for_idle(struct lx6464es * chip,u32 pipe,int is_capture)64502bec490STim Blechmann int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture)
64602bec490STim Blechmann {
64702bec490STim Blechmann return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE);
64802bec490STim Blechmann }
64902bec490STim Blechmann
65002bec490STim Blechmann /* low-level stream handling */
lx_stream_set_state(struct lx6464es * chip,u32 pipe,int is_capture,enum stream_state_t state)65102bec490STim Blechmann int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
65202bec490STim Blechmann int is_capture, enum stream_state_t state)
65302bec490STim Blechmann {
65402bec490STim Blechmann int err;
65502bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
65602bec490STim Blechmann
6576336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
65802bec490STim Blechmann lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE);
65902bec490STim Blechmann
66002bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
66102bec490STim Blechmann chip->rmh.cmd[0] |= state;
66202bec490STim Blechmann
66302bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
6646336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
66502bec490STim Blechmann
66602bec490STim Blechmann return err;
66702bec490STim Blechmann }
66802bec490STim Blechmann
lx_stream_set_format(struct lx6464es * chip,struct snd_pcm_runtime * runtime,u32 pipe,int is_capture)66902bec490STim Blechmann int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
67002bec490STim Blechmann u32 pipe, int is_capture)
67102bec490STim Blechmann {
67202bec490STim Blechmann int err;
67302bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
67402bec490STim Blechmann u32 channels = runtime->channels;
67502bec490STim Blechmann
6766336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
67702bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
67802bec490STim Blechmann
67902bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
68002bec490STim Blechmann
68102bec490STim Blechmann if (runtime->sample_bits == 16)
68202bec490STim Blechmann /* 16 bit format */
68302bec490STim Blechmann chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET);
68402bec490STim Blechmann
68502bec490STim Blechmann if (snd_pcm_format_little_endian(runtime->format))
68602bec490STim Blechmann /* little endian/intel format */
68702bec490STim Blechmann chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET);
68802bec490STim Blechmann
68902bec490STim Blechmann chip->rmh.cmd[0] |= channels-1;
69002bec490STim Blechmann
69102bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
6926336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
69302bec490STim Blechmann
69402bec490STim Blechmann return err;
69502bec490STim Blechmann }
69602bec490STim Blechmann
lx_stream_state(struct lx6464es * chip,u32 pipe,int is_capture,int * rstate)69702bec490STim Blechmann int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
69802bec490STim Blechmann int *rstate)
69902bec490STim Blechmann {
70002bec490STim Blechmann int err;
70102bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
70202bec490STim Blechmann
7036336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
70402bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
70502bec490STim Blechmann
70602bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
70702bec490STim Blechmann
70802bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
70902bec490STim Blechmann
71002bec490STim Blechmann *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE;
71102bec490STim Blechmann
7126336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
71302bec490STim Blechmann return err;
71402bec490STim Blechmann }
71502bec490STim Blechmann
lx_stream_sample_position(struct lx6464es * chip,u32 pipe,int is_capture,u64 * r_bytepos)71602bec490STim Blechmann int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
71702bec490STim Blechmann u64 *r_bytepos)
71802bec490STim Blechmann {
71902bec490STim Blechmann int err;
72002bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
72102bec490STim Blechmann
7226336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
72302bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
72402bec490STim Blechmann
72502bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
72602bec490STim Blechmann
72702bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
72802bec490STim Blechmann
72902bec490STim Blechmann *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
73002bec490STim Blechmann << 32) /* hi part */
73102bec490STim Blechmann + chip->rmh.stat[1]; /* lo part */
73202bec490STim Blechmann
7336336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
73402bec490STim Blechmann return err;
73502bec490STim Blechmann }
73602bec490STim Blechmann
73702bec490STim Blechmann /* low-level buffer handling */
lx_buffer_give(struct lx6464es * chip,u32 pipe,int is_capture,u32 buffer_size,u32 buf_address_lo,u32 buf_address_hi,u32 * r_buffer_index)73802bec490STim Blechmann int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
73902bec490STim Blechmann u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi,
74002bec490STim Blechmann u32 *r_buffer_index)
74102bec490STim Blechmann {
74202bec490STim Blechmann int err;
74302bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
74402bec490STim Blechmann
7456336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
74602bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER);
74702bec490STim Blechmann
74802bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
74902bec490STim Blechmann chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */
75002bec490STim Blechmann
75102bec490STim Blechmann /* todo: pause request, circular buffer */
75202bec490STim Blechmann
75302bec490STim Blechmann chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE;
75402bec490STim Blechmann chip->rmh.cmd[2] = buf_address_lo;
75502bec490STim Blechmann
75602bec490STim Blechmann if (buf_address_hi) {
75702bec490STim Blechmann chip->rmh.cmd_len = 4;
75802bec490STim Blechmann chip->rmh.cmd[3] = buf_address_hi;
75902bec490STim Blechmann chip->rmh.cmd[0] |= BF_64BITS_ADR;
76002bec490STim Blechmann }
76102bec490STim Blechmann
76202bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
76302bec490STim Blechmann
76402bec490STim Blechmann if (err == 0) {
76502bec490STim Blechmann *r_buffer_index = chip->rmh.stat[0];
76602bec490STim Blechmann goto done;
76702bec490STim Blechmann }
76802bec490STim Blechmann
76902bec490STim Blechmann if (err == EB_RBUFFERS_TABLE_OVERFLOW)
770be4e6d3cSTakashi Iwai dev_err(chip->card->dev,
771be4e6d3cSTakashi Iwai "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
77202bec490STim Blechmann
77302bec490STim Blechmann if (err == EB_INVALID_STREAM)
774be4e6d3cSTakashi Iwai dev_err(chip->card->dev,
775be4e6d3cSTakashi Iwai "lx_buffer_give EB_INVALID_STREAM\n");
77602bec490STim Blechmann
77702bec490STim Blechmann if (err == EB_CMD_REFUSED)
778be4e6d3cSTakashi Iwai dev_err(chip->card->dev,
779be4e6d3cSTakashi Iwai "lx_buffer_give EB_CMD_REFUSED\n");
78002bec490STim Blechmann
78102bec490STim Blechmann done:
7826336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
78302bec490STim Blechmann return err;
78402bec490STim Blechmann }
78502bec490STim Blechmann
lx_buffer_free(struct lx6464es * chip,u32 pipe,int is_capture,u32 * r_buffer_size)78602bec490STim Blechmann int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
78702bec490STim Blechmann u32 *r_buffer_size)
78802bec490STim Blechmann {
78902bec490STim Blechmann int err;
79002bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
79102bec490STim Blechmann
7926336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
79302bec490STim Blechmann lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
79402bec490STim Blechmann
79502bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
79602bec490STim Blechmann chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the
79702bec490STim Blechmann * microblaze will seek for it */
79802bec490STim Blechmann
79902bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
80002bec490STim Blechmann
80102bec490STim Blechmann if (err == 0)
80202bec490STim Blechmann *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE;
80302bec490STim Blechmann
8046336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
80502bec490STim Blechmann return err;
80602bec490STim Blechmann }
80702bec490STim Blechmann
lx_buffer_cancel(struct lx6464es * chip,u32 pipe,int is_capture,u32 buffer_index)80802bec490STim Blechmann int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
80902bec490STim Blechmann u32 buffer_index)
81002bec490STim Blechmann {
81102bec490STim Blechmann int err;
81202bec490STim Blechmann u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
81302bec490STim Blechmann
8146336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
81502bec490STim Blechmann lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
81602bec490STim Blechmann
81702bec490STim Blechmann chip->rmh.cmd[0] |= pipe_cmd;
81802bec490STim Blechmann chip->rmh.cmd[0] |= buffer_index;
81902bec490STim Blechmann
82002bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
82102bec490STim Blechmann
8226336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
82302bec490STim Blechmann return err;
82402bec490STim Blechmann }
82502bec490STim Blechmann
82602bec490STim Blechmann
82702bec490STim Blechmann /* low-level gain/peak handling
82802bec490STim Blechmann *
82902bec490STim Blechmann * \todo: can we unmute capture/playback channels independently?
83002bec490STim Blechmann *
83102bec490STim Blechmann * */
lx_level_unmute(struct lx6464es * chip,int is_capture,int unmute)83202bec490STim Blechmann int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
83302bec490STim Blechmann {
83402bec490STim Blechmann int err;
83502bec490STim Blechmann /* bit set to 1: channel muted */
83602bec490STim Blechmann u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU;
83702bec490STim Blechmann
8386336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
83902bec490STim Blechmann lx_message_init(&chip->rmh, CMD_0D_SET_MUTE);
84002bec490STim Blechmann
84102bec490STim Blechmann chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0);
84202bec490STim Blechmann
84302bec490STim Blechmann chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */
84402bec490STim Blechmann chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */
84502bec490STim Blechmann
846be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev,
847be4e6d3cSTakashi Iwai "mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
84802bec490STim Blechmann chip->rmh.cmd[2]);
84902bec490STim Blechmann
85002bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
85102bec490STim Blechmann
8526336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
85302bec490STim Blechmann return err;
85402bec490STim Blechmann }
85502bec490STim Blechmann
8562f200ce2STakashi Iwai static const u32 peak_map[] = {
85702bec490STim Blechmann 0x00000109, /* -90.308dB */
85802bec490STim Blechmann 0x0000083B, /* -72.247dB */
85902bec490STim Blechmann 0x000020C4, /* -60.205dB */
86002bec490STim Blechmann 0x00008273, /* -48.030dB */
86102bec490STim Blechmann 0x00020756, /* -36.005dB */
86202bec490STim Blechmann 0x00040C37, /* -30.001dB */
86302bec490STim Blechmann 0x00081385, /* -24.002dB */
86402bec490STim Blechmann 0x00101D3F, /* -18.000dB */
86502bec490STim Blechmann 0x0016C310, /* -15.000dB */
86602bec490STim Blechmann 0x002026F2, /* -12.001dB */
86702bec490STim Blechmann 0x002D6A86, /* -9.000dB */
86802bec490STim Blechmann 0x004026E6, /* -6.004dB */
86902bec490STim Blechmann 0x005A9DF6, /* -3.000dB */
87002bec490STim Blechmann 0x0065AC8B, /* -2.000dB */
87102bec490STim Blechmann 0x00721481, /* -1.000dB */
87202bec490STim Blechmann 0x007FFFFF, /* FS */
87302bec490STim Blechmann };
87402bec490STim Blechmann
lx_level_peaks(struct lx6464es * chip,int is_capture,int channels,u32 * r_levels)87502bec490STim Blechmann int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
87602bec490STim Blechmann u32 *r_levels)
87702bec490STim Blechmann {
87802bec490STim Blechmann int err = 0;
87902bec490STim Blechmann int i;
88002bec490STim Blechmann
8816336c20cSTakashi Iwai mutex_lock(&chip->msg_lock);
88202bec490STim Blechmann for (i = 0; i < channels; i += 4) {
88302bec490STim Blechmann u32 s0, s1, s2, s3;
88402bec490STim Blechmann
88502bec490STim Blechmann lx_message_init(&chip->rmh, CMD_12_GET_PEAK);
88602bec490STim Blechmann chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i);
88702bec490STim Blechmann
88802bec490STim Blechmann err = lx_message_send_atomic(chip, &chip->rmh);
88902bec490STim Blechmann
89002bec490STim Blechmann if (err == 0) {
89102bec490STim Blechmann s0 = peak_map[chip->rmh.stat[0] & 0x0F];
89202bec490STim Blechmann s1 = peak_map[(chip->rmh.stat[0] >> 4) & 0xf];
89302bec490STim Blechmann s2 = peak_map[(chip->rmh.stat[0] >> 8) & 0xf];
89402bec490STim Blechmann s3 = peak_map[(chip->rmh.stat[0] >> 12) & 0xf];
89502bec490STim Blechmann } else
89602bec490STim Blechmann s0 = s1 = s2 = s3 = 0;
89702bec490STim Blechmann
89802bec490STim Blechmann r_levels[0] = s0;
89902bec490STim Blechmann r_levels[1] = s1;
90002bec490STim Blechmann r_levels[2] = s2;
90102bec490STim Blechmann r_levels[3] = s3;
90202bec490STim Blechmann
90302bec490STim Blechmann r_levels += 4;
90402bec490STim Blechmann }
90502bec490STim Blechmann
9066336c20cSTakashi Iwai mutex_unlock(&chip->msg_lock);
90702bec490STim Blechmann return err;
90802bec490STim Blechmann }
90902bec490STim Blechmann
91002bec490STim Blechmann /* interrupt handling */
91102bec490STim Blechmann #define PCX_IRQ_NONE 0
912c546ca95SMaxime Ripard #define IRQCS_ACTIVE_PCIDB BIT(13)
913c546ca95SMaxime Ripard #define IRQCS_ENABLE_PCIIRQ BIT(8)
914c546ca95SMaxime Ripard #define IRQCS_ENABLE_PCIDB BIT(9)
91502bec490STim Blechmann
lx_interrupt_test_ack(struct lx6464es * chip)91602bec490STim Blechmann static u32 lx_interrupt_test_ack(struct lx6464es *chip)
91702bec490STim Blechmann {
91802bec490STim Blechmann u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS);
91902bec490STim Blechmann
92002bec490STim Blechmann /* Test if PCI Doorbell interrupt is active */
92102bec490STim Blechmann if (irqcs & IRQCS_ACTIVE_PCIDB) {
92202bec490STim Blechmann u32 temp;
92302bec490STim Blechmann irqcs = PCX_IRQ_NONE;
92402bec490STim Blechmann
92502bec490STim Blechmann while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) {
92602bec490STim Blechmann /* RAZ interrupt */
92702bec490STim Blechmann irqcs |= temp;
92802bec490STim Blechmann lx_plx_reg_write(chip, ePLX_L2PCIDB, temp);
92902bec490STim Blechmann }
93002bec490STim Blechmann
93102bec490STim Blechmann return irqcs;
93202bec490STim Blechmann }
93302bec490STim Blechmann return PCX_IRQ_NONE;
93402bec490STim Blechmann }
93502bec490STim Blechmann
lx_interrupt_ack(struct lx6464es * chip,u32 * r_irqsrc,int * r_async_pending,int * r_async_escmd)93602bec490STim Blechmann static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc,
93702bec490STim Blechmann int *r_async_pending, int *r_async_escmd)
93802bec490STim Blechmann {
93902bec490STim Blechmann u32 irq_async;
94002bec490STim Blechmann u32 irqsrc = lx_interrupt_test_ack(chip);
94102bec490STim Blechmann
94202bec490STim Blechmann if (irqsrc == PCX_IRQ_NONE)
94302bec490STim Blechmann return 0;
94402bec490STim Blechmann
94502bec490STim Blechmann *r_irqsrc = irqsrc;
94602bec490STim Blechmann
94702bec490STim Blechmann irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response
94802bec490STim Blechmann * (set by xilinx) + EOB */
94902bec490STim Blechmann
95002bec490STim Blechmann if (irq_async & MASK_SYS_STATUS_ESA) {
95102bec490STim Blechmann irq_async &= ~MASK_SYS_STATUS_ESA;
95202bec490STim Blechmann *r_async_escmd = 1;
95302bec490STim Blechmann }
95402bec490STim Blechmann
95502bec490STim Blechmann if (irq_async) {
956be4e6d3cSTakashi Iwai /* dev_dbg(chip->card->dev, "interrupt: async event pending\n"); */
95702bec490STim Blechmann *r_async_pending = 1;
95802bec490STim Blechmann }
95902bec490STim Blechmann
96002bec490STim Blechmann return 1;
96102bec490STim Blechmann }
96202bec490STim Blechmann
lx_interrupt_handle_async_events(struct lx6464es * chip,u32 irqsrc,int * r_freq_changed,u64 * r_notified_in_pipe_mask,u64 * r_notified_out_pipe_mask)96302bec490STim Blechmann static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
96402bec490STim Blechmann int *r_freq_changed,
96502bec490STim Blechmann u64 *r_notified_in_pipe_mask,
96602bec490STim Blechmann u64 *r_notified_out_pipe_mask)
96702bec490STim Blechmann {
96802bec490STim Blechmann int err;
96902bec490STim Blechmann u32 stat[9]; /* answer from CMD_04_GET_EVENT */
97002bec490STim Blechmann
97138137a06SMaxime Ripard /* We can optimize this to not read dumb events.
97238137a06SMaxime Ripard * Answer words are in the following order:
97338137a06SMaxime Ripard * Stat[0] general status
97438137a06SMaxime Ripard * Stat[1] end of buffer OUT pF
97538137a06SMaxime Ripard * Stat[2] end of buffer OUT pf
97638137a06SMaxime Ripard * Stat[3] end of buffer IN pF
97738137a06SMaxime Ripard * Stat[4] end of buffer IN pf
97838137a06SMaxime Ripard * Stat[5] MSB underrun
97938137a06SMaxime Ripard * Stat[6] LSB underrun
98038137a06SMaxime Ripard * Stat[7] MSB overrun
98138137a06SMaxime Ripard * Stat[8] LSB overrun
98202bec490STim Blechmann * */
98302bec490STim Blechmann
98402bec490STim Blechmann int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
98502bec490STim Blechmann int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
98602bec490STim Blechmann
98702bec490STim Blechmann *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0;
98802bec490STim Blechmann
98902bec490STim Blechmann err = lx_dsp_read_async_events(chip, stat);
99002bec490STim Blechmann if (err < 0)
99102bec490STim Blechmann return err;
99202bec490STim Blechmann
99302bec490STim Blechmann if (eb_pending_in) {
99402bec490STim Blechmann *r_notified_in_pipe_mask = ((u64)stat[3] << 32)
99502bec490STim Blechmann + stat[4];
996be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "interrupt: EOBI pending %llx\n",
99702bec490STim Blechmann *r_notified_in_pipe_mask);
99802bec490STim Blechmann }
99902bec490STim Blechmann if (eb_pending_out) {
100002bec490STim Blechmann *r_notified_out_pipe_mask = ((u64)stat[1] << 32)
100102bec490STim Blechmann + stat[2];
1002be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "interrupt: EOBO pending %llx\n",
100302bec490STim Blechmann *r_notified_out_pipe_mask);
100402bec490STim Blechmann }
100502bec490STim Blechmann
100602bec490STim Blechmann /* todo: handle xrun notification */
100702bec490STim Blechmann
100802bec490STim Blechmann return err;
100902bec490STim Blechmann }
101002bec490STim Blechmann
lx_interrupt_request_new_buffer(struct lx6464es * chip,struct lx_stream * lx_stream)101102bec490STim Blechmann static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
101202bec490STim Blechmann struct lx_stream *lx_stream)
101302bec490STim Blechmann {
101402bec490STim Blechmann struct snd_pcm_substream *substream = lx_stream->stream;
1015f7467452STim Blechmann const unsigned int is_capture = lx_stream->is_capture;
101602bec490STim Blechmann int err;
101702bec490STim Blechmann
101802bec490STim Blechmann const u32 channels = substream->runtime->channels;
101902bec490STim Blechmann const u32 bytes_per_frame = channels * 3;
102002bec490STim Blechmann const u32 period_size = substream->runtime->period_size;
102102bec490STim Blechmann const u32 period_bytes = period_size * bytes_per_frame;
102202bec490STim Blechmann const u32 pos = lx_stream->frame_pos;
102302bec490STim Blechmann const u32 next_pos = ((pos+1) == substream->runtime->periods) ?
102402bec490STim Blechmann 0 : pos + 1;
102502bec490STim Blechmann
102602bec490STim Blechmann dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes;
102702bec490STim Blechmann u32 buf_hi = 0;
102802bec490STim Blechmann u32 buf_lo = 0;
102902bec490STim Blechmann u32 buffer_index = 0;
103002bec490STim Blechmann
103102bec490STim Blechmann u32 needed, freed;
103202bec490STim Blechmann u32 size_array[MAX_STREAM_BUFFER];
103302bec490STim Blechmann
1034be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n");
103502bec490STim Blechmann
10366336c20cSTakashi Iwai mutex_lock(&chip->lock);
103702bec490STim Blechmann
103802bec490STim Blechmann err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
1039be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev,
1040be4e6d3cSTakashi Iwai "interrupt: needed %d, freed %d\n", needed, freed);
104102bec490STim Blechmann
104202bec490STim Blechmann unpack_pointer(buf, &buf_lo, &buf_hi);
104302bec490STim Blechmann err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi,
104402bec490STim Blechmann &buffer_index);
1045be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev,
1046be4e6d3cSTakashi Iwai "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n",
1047293db842STakashi Iwai buffer_index, (unsigned long)buf, period_bytes);
104802bec490STim Blechmann
104902bec490STim Blechmann lx_stream->frame_pos = next_pos;
10506336c20cSTakashi Iwai mutex_unlock(&chip->lock);
105102bec490STim Blechmann
105202bec490STim Blechmann return err;
105302bec490STim Blechmann }
105402bec490STim Blechmann
lx_interrupt(int irq,void * dev_id)105502bec490STim Blechmann irqreturn_t lx_interrupt(int irq, void *dev_id)
105602bec490STim Blechmann {
105702bec490STim Blechmann struct lx6464es *chip = dev_id;
105802bec490STim Blechmann int async_pending, async_escmd;
105902bec490STim Blechmann u32 irqsrc;
10606336c20cSTakashi Iwai bool wake_thread = false;
106102bec490STim Blechmann
1062be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev,
1063be4e6d3cSTakashi Iwai "**************************************************\n");
106402bec490STim Blechmann
106502bec490STim Blechmann if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
1066be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "IRQ_NONE\n");
106702bec490STim Blechmann return IRQ_NONE; /* this device did not cause the interrupt */
106802bec490STim Blechmann }
106902bec490STim Blechmann
107002bec490STim Blechmann if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
10716336c20cSTakashi Iwai return IRQ_HANDLED;
107202bec490STim Blechmann
107302bec490STim Blechmann if (irqsrc & MASK_SYS_STATUS_EOBI)
107468e440bbSMaxime Ripard dev_dbg(chip->card->dev, "interrupt: EOBI\n");
107502bec490STim Blechmann
107602bec490STim Blechmann if (irqsrc & MASK_SYS_STATUS_EOBO)
1077be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "interrupt: EOBO\n");
107802bec490STim Blechmann
107902bec490STim Blechmann if (irqsrc & MASK_SYS_STATUS_URUN)
1080be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "interrupt: URUN\n");
108102bec490STim Blechmann
108202bec490STim Blechmann if (irqsrc & MASK_SYS_STATUS_ORUN)
1083be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "interrupt: ORUN\n");
108402bec490STim Blechmann
108502bec490STim Blechmann if (async_pending) {
10866336c20cSTakashi Iwai wake_thread = true;
10876336c20cSTakashi Iwai chip->irqsrc = irqsrc;
108802bec490STim Blechmann }
108902bec490STim Blechmann
109002bec490STim Blechmann if (async_escmd) {
109102bec490STim Blechmann /* backdoor for ethersound commands
109202bec490STim Blechmann *
109302bec490STim Blechmann * for now, we do not need this
109402bec490STim Blechmann *
109502bec490STim Blechmann * */
109602bec490STim Blechmann
1097be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
109802bec490STim Blechmann }
109902bec490STim Blechmann
11006336c20cSTakashi Iwai return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
11016336c20cSTakashi Iwai }
11026336c20cSTakashi Iwai
lx_threaded_irq(int irq,void * dev_id)11036336c20cSTakashi Iwai irqreturn_t lx_threaded_irq(int irq, void *dev_id)
11046336c20cSTakashi Iwai {
11056336c20cSTakashi Iwai struct lx6464es *chip = dev_id;
11066336c20cSTakashi Iwai u64 notified_in_pipe_mask = 0;
11076336c20cSTakashi Iwai u64 notified_out_pipe_mask = 0;
11086336c20cSTakashi Iwai int freq_changed;
11096336c20cSTakashi Iwai int err;
11106336c20cSTakashi Iwai
11116336c20cSTakashi Iwai /* handle async events */
11126336c20cSTakashi Iwai err = lx_interrupt_handle_async_events(chip, chip->irqsrc,
11136336c20cSTakashi Iwai &freq_changed,
11146336c20cSTakashi Iwai ¬ified_in_pipe_mask,
11156336c20cSTakashi Iwai ¬ified_out_pipe_mask);
11166336c20cSTakashi Iwai if (err)
11176336c20cSTakashi Iwai dev_err(chip->card->dev, "error handling async events\n");
11186336c20cSTakashi Iwai
11196336c20cSTakashi Iwai if (notified_in_pipe_mask) {
11206336c20cSTakashi Iwai struct lx_stream *lx_stream = &chip->capture_stream;
11216336c20cSTakashi Iwai
11226336c20cSTakashi Iwai dev_dbg(chip->card->dev,
11236336c20cSTakashi Iwai "requesting audio transfer for capture\n");
11246336c20cSTakashi Iwai err = lx_interrupt_request_new_buffer(chip, lx_stream);
11256336c20cSTakashi Iwai if (err < 0)
11266336c20cSTakashi Iwai dev_err(chip->card->dev,
11276336c20cSTakashi Iwai "cannot request new buffer for capture\n");
11286336c20cSTakashi Iwai snd_pcm_period_elapsed(lx_stream->stream);
11296336c20cSTakashi Iwai }
11306336c20cSTakashi Iwai
11316336c20cSTakashi Iwai if (notified_out_pipe_mask) {
11326336c20cSTakashi Iwai struct lx_stream *lx_stream = &chip->playback_stream;
11336336c20cSTakashi Iwai
11346336c20cSTakashi Iwai dev_dbg(chip->card->dev,
11356336c20cSTakashi Iwai "requesting audio transfer for playback\n");
11366336c20cSTakashi Iwai err = lx_interrupt_request_new_buffer(chip, lx_stream);
11376336c20cSTakashi Iwai if (err < 0)
11386336c20cSTakashi Iwai dev_err(chip->card->dev,
11396336c20cSTakashi Iwai "cannot request new buffer for playback\n");
11406336c20cSTakashi Iwai snd_pcm_period_elapsed(lx_stream->stream);
11416336c20cSTakashi Iwai }
11426336c20cSTakashi Iwai
11436336c20cSTakashi Iwai return IRQ_HANDLED;
114402bec490STim Blechmann }
114502bec490STim Blechmann
114602bec490STim Blechmann
lx_irq_set(struct lx6464es * chip,int enable)114702bec490STim Blechmann static void lx_irq_set(struct lx6464es *chip, int enable)
114802bec490STim Blechmann {
114902bec490STim Blechmann u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS);
115002bec490STim Blechmann
115102bec490STim Blechmann /* enable/disable interrupts
115202bec490STim Blechmann *
115302bec490STim Blechmann * Set the Doorbell and PCI interrupt enable bits
115402bec490STim Blechmann *
115502bec490STim Blechmann * */
115602bec490STim Blechmann if (enable)
115702bec490STim Blechmann reg |= (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB);
115802bec490STim Blechmann else
115902bec490STim Blechmann reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB);
116002bec490STim Blechmann lx_plx_reg_write(chip, ePLX_IRQCS, reg);
116102bec490STim Blechmann }
116202bec490STim Blechmann
lx_irq_enable(struct lx6464es * chip)116302bec490STim Blechmann void lx_irq_enable(struct lx6464es *chip)
116402bec490STim Blechmann {
1165be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "->lx_irq_enable\n");
116602bec490STim Blechmann lx_irq_set(chip, 1);
116702bec490STim Blechmann }
116802bec490STim Blechmann
lx_irq_disable(struct lx6464es * chip)116902bec490STim Blechmann void lx_irq_disable(struct lx6464es *chip)
117002bec490STim Blechmann {
1171be4e6d3cSTakashi Iwai dev_dbg(chip->card->dev, "->lx_irq_disable\n");
117202bec490STim Blechmann lx_irq_set(chip, 0);
117302bec490STim Blechmann }
1174