Tool/software: Linux
Hi.
I trying to read MCASP polling RBUF. But, everytime RBUF is read Zero.
I expect when MCASP receive data RDATA bit will be set. So I check it, but it was never set.
I do not know what is problem. Plz. check my source code.
And is there any example to read MCASP.
Thank you
- block
- source code
mcasp_open() -> audio_init() -> audio_run(); -> check rx state or RBUF
/*
BodyFriend kdj6724
mcasp_audio.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <asm/page.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <asm/io.h>
#include "mcasp_audio.h"
static int mcasp_major = 0;
module_param(mcasp_major, int, 0);
#define SYS_INT_EDMA 20
#define SYS_INT_MCATXINT0 (80)
#define SYS_INT_MCARXINT0 (81)
#define SYS_INT_MCATXINT1 (82)
#define SYS_INT_MCARXINT1 (83)
struct mcasp_edma_cc {
struct device *dev;
struct edma_soc_info *info;
void __iomem *base;
int id;
bool legacy_mode;
/* eDMA3 resource information */
unsigned num_channels;
unsigned num_qchannels;
unsigned num_region;
unsigned num_slots;
unsigned num_tc;
bool chmap_exist;
//enum dma_event_q default_queue;
/*
* The slot_inuse bit for each PaRAM slot is clear unless the slot is
* in use by Linux or if it is allocated to be used by DSP.
*/
unsigned long *slot_inuse;
struct dma_device dma_slave;
struct dma_device *dma_memcpy;
struct edma_chan *slave_chans;
struct edma_tc *tc_list;
int dummy_slot;
};
/******************************************************************************
** INTERNAL MACRO DEFINITIONS
******************************************************************************/
/*
** Values which are configurable
*/
/* Slot size to send/receive data */
#define SLOT_SIZE 32
/* Word size to send/receive data. Word size <= Slot size */
#define WORD_SIZE 24
/* Sampling Rate which will be used by both transmit and receive sections */
#define SAMPLING_RATE (44100u)
/* Number of channels, L & R */
#define NUM_I2S_CHANNELS (2u)
/* Number of samples to be used per audio buffer */
#define NUM_SAMPLES_PER_AUDIO_BUF (2000u)
/* Number of buffers used per tx/rx */
#define NUM_BUF (3u)
/* Number of linked parameter set used per tx/rx */
#define NUM_PAR (2u)
/* Specify where the parameter set starting is */
#define PAR_ID_START (70u)
/* Number of samples in loop buffer */
#define NUM_SAMPLES_LOOP_BUF (10u)
/* AIC3106 codec address */
#define I2C_SLAVE_CODEC_AIC31 (0x1Bu)
/* McASP Serializer for Receive */
#define MCASP_XSER_RX (1u)
/* McASP Serializer for Transmit */
#define MCASP_XSER_TX (0u)
/*
** Below Macros are calculated based on the above inputs
*/
#define NUM_TX_SERIALIZERS ((NUM_I2S_CHANNELS >> 1) \
+ (NUM_I2S_CHANNELS & 0x01))
#define NUM_RX_SERIALIZERS ((NUM_I2S_CHANNELS >> 1) \
+ (NUM_I2S_CHANNELS & 0x01))
#define I2S_SLOTS ((1 << NUM_I2S_CHANNELS) - 1)
#define BYTES_PER_SAMPLE ((WORD_SIZE >> 3) \
* NUM_I2S_CHANNELS)
#define AUDIO_BUF_SIZE (NUM_SAMPLES_PER_AUDIO_BUF \
* BYTES_PER_SAMPLE)
#define TX_DMA_INT_ENABLE (EDMA3CC_OPT_TCC_SET \
(EDMA3_CHA_MCASP1_TX) | (1 \
<< EDMA3CC_OPT_TCINTEN_SHIFT))
#define RX_DMA_INT_ENABLE (EDMA3CC_OPT_TCC_SET \
(EDMA3_CHA_MCASP1_RX) | (1 \
<< EDMA3CC_OPT_TCINTEN_SHIFT))
#define PAR_RX_START (PAR_ID_START)
#define PAR_TX_START (PAR_RX_START + NUM_PAR)
/*
** Definitions which are not configurable
*/
#define SIZE_PARAMSET (32u)
#define OPT_FIFO_WIDTH (0x02 << 8u)
void __iomem *mcasp0_base;
void __iomem *mcasp1_base;
void __iomem *ctrl_base;
void __iomem *cmper_base;
void __iomem *edma3ch_base; // edma3 channel controller
void __iomem *edma3ch0_base; // edma3 channel1 controller
void __iomem *edma3ch1_base; // edma3 channel2 controller
void __iomem *edma3ch2_base; // edma3 channel3 controller
/******************************************************************************
** INTERNAL VARIABLE DEFINITIONS
******************************************************************************/
static unsigned char loopBuf[NUM_SAMPLES_LOOP_BUF * BYTES_PER_SAMPLE] = {0};
/*
** Transmit buffers. If any new buffer is to be added, define it here and
** update the NUM_BUF.
*/
static unsigned char txBuf0[AUDIO_BUF_SIZE];
static unsigned char txBuf1[AUDIO_BUF_SIZE];
static unsigned char txBuf2[AUDIO_BUF_SIZE];
/*
** Receive buffers. If any new buffer is to be added, define it here and
** update the NUM_BUF.
*/
static unsigned char rxBuf0[AUDIO_BUF_SIZE];
static unsigned char rxBuf1[AUDIO_BUF_SIZE];
static unsigned char rxBuf2[AUDIO_BUF_SIZE];
/*
** Next buffer to receive data. The data will be received in this buffer.
*/
static volatile unsigned int nxtBufToRcv = 0;
/*
** The RX buffer which filled latest.
*/
static volatile unsigned int lastFullRxBuf = 0;
/*
** The offset of the paRAM ID, from the starting of the paRAM set.
*/
static volatile unsigned short parOffRcvd = 0;
/*
** The offset of the paRAM ID sent, from starting of the paRAM set.
*/
static volatile unsigned short parOffSent = 0;
/*
** The transmit buffer which was sent last.
*/
static volatile unsigned int lastSentTxBuf = NUM_BUF - 1;
/*
** The offset of the paRAM ID to be sent next, from starting of the paRAM set.
*/
static volatile unsigned short parOffTxToSend = 0;
/******************************************************************************
** INTERNAL CONSTATNT DEFINITIONS
******************************************************************************/
/* Array of receive buffer pointers */
static unsigned int const rxBufPtr[NUM_BUF] =
{
(unsigned int) rxBuf0,
(unsigned int) rxBuf1,
(unsigned int) rxBuf2
};
/* Array of transmit buffer pointers */
static unsigned int const txBufPtr[NUM_BUF] =
{
(unsigned int) txBuf0,
(unsigned int) txBuf1,
(unsigned int) txBuf2
};
/*
** Default paRAM for Transmit section. This will be transmitting from
** a loop buffer.
*/
static struct EDMA3CCPaRAMEntry const txDefaultPar =
{
(unsigned int)(OPT_FIFO_WIDTH), /* Opt field */
(unsigned int)loopBuf, /* source address */
(unsigned short)(BYTES_PER_SAMPLE), /* aCnt */
(unsigned short)(NUM_SAMPLES_LOOP_BUF), /* bCnt */
(unsigned int) SOC_MCASP_1_DATA_REGS, /* dest address */
(short) (BYTES_PER_SAMPLE), /* source bIdx */
(short)(0), /* dest bIdx */
(unsigned short)(PAR_TX_START * SIZE_PARAMSET), /* link address */
(unsigned short)(0), /* bCnt reload value */
(short)(0), /* source cIdx */
(short)(0), /* dest cIdx */
(unsigned short)1 /* cCnt */
};
/*
** Default paRAM for Receive section.
*/
static struct EDMA3CCPaRAMEntry const rxDefaultPar =
{
(unsigned int)(OPT_FIFO_WIDTH), /* Opt field */
(unsigned int)SOC_MCASP_1_DATA_REGS, /* source address */
(unsigned short)(BYTES_PER_SAMPLE), /* aCnt */
(unsigned short)(1), /* bCnt */
(unsigned int)rxBuf0, /* dest address */
(short) (0), /* source bIdx */
(short)(BYTES_PER_SAMPLE), /* dest bIdx */
(unsigned short)(PAR_RX_START * SIZE_PARAMSET), /* link address */
(unsigned short)(0), /* bCnt reload value */
(short)(0), /* source cIdx */
(short)(0), /* dest cIdx */
(unsigned short)1 /* cCnt */
};
/******************************************************************************
** FUNCTION DEFINITIONS
******************************************************************************/
/*
** Assigns loop job for a parameter set
*/
static void ParamTxLoopJobSet(volatile void __iomem *dmaAddr, unsigned short parId)
{
EDMA3CCPaRAMEntry paramSet;
memcpy(¶mSet, &txDefaultPar, SIZE_PARAMSET - 2);
/* link the paRAM to itself */
paramSet.linkAddr = parId * SIZE_PARAMSET;
EDMA3SetPaRAM(dmaAddr, parId, ¶mSet);
}
/*
** Initializes the DMA parameters.
** The RX basic paRAM set(channel) is 0 and TX basic paRAM set (channel) is 1.
**
** The RX paRAM set 0 will be initialized to receive data in the rx buffer 0.
** The transfer completion interrupt will not be enabled for paRAM set 0;
** paRAM set 0 will be linked to linked paRAM set starting (PAR_RX_START) of RX.
** and further reception only happens via linked paRAM set.
** For example, if the PAR_RX_START value is 40, and the number of paRAMS is 2,
** reception paRAM set linking will be initialized as 0-->40-->41-->40
**
** The TX paRAM sets will be initialized to transmit from the loop buffer.
** The size of the loop buffer can be configured.
** The transfer completion interrupt will not be enabled for paRAM set 1;
** paRAM set 1 will be linked to linked paRAM set starting (PAR_TX_START) of TX.
** All other paRAM sets will be linked to itself.
** and further transmission only happens via linked paRAM set.
** For example, if the PAR_RX_START value is 42, and the number of paRAMS is 2,
** So transmission paRAM set linking will be initialized as 1-->42-->42, 43->43.
*/
static void I2SDMAParamInit(volatile void __iomem *dmaAddr)
{
EDMA3CCPaRAMEntry paramSet;
int idx;
/* Initialize the 0th paRAM set for receive */
memcpy(¶mSet, &rxDefaultPar, SIZE_PARAMSET - 2);
EDMA3SetPaRAM(dmaAddr, EDMA3_CHA_MCASP1_RX, ¶mSet);
/* further paramsets, enable interrupt */
paramSet.opt |= RX_DMA_INT_ENABLE;
for(idx = 0 ; idx < NUM_PAR; idx++)
{
paramSet.destAddr = rxBufPtr[idx];
paramSet.linkAddr = (PAR_RX_START + ((idx + 1) % NUM_PAR))
* (SIZE_PARAMSET);
paramSet.bCnt = NUM_SAMPLES_PER_AUDIO_BUF;
/*
** for the first linked paRAM set, start receiving the second
** sample only since the first sample is already received in
** rx buffer 0 itself.
*/
if( 0 == idx)
{
paramSet.destAddr += BYTES_PER_SAMPLE;
paramSet.bCnt -= BYTES_PER_SAMPLE;
}
EDMA3SetPaRAM(dmaAddr, (PAR_RX_START + idx), ¶mSet);
}
/* Initialize the required variables for reception */
nxtBufToRcv = idx % NUM_BUF;
lastFullRxBuf = NUM_BUF - 1;
parOffRcvd = 0;
/* Initialize the 1st paRAM set for transmit */
memcpy(¶mSet, &txDefaultPar, SIZE_PARAMSET - 2);
EDMA3SetPaRAM(dmaAddr, EDMA3_CHA_MCASP1_TX, ¶mSet);
/* rest of the params, enable loop job */
for(idx = 0 ; idx < NUM_PAR; idx++)
{
ParamTxLoopJobSet(dmaAddr, PAR_TX_START + idx);
}
/* Initialize the variables for transmit */
parOffSent = 0;
lastSentTxBuf = NUM_BUF - 1;
}
/*
** Configures the McASP Transmit Section in I2S mode.
*/
static void McASPI2STxConfigure(volatile void __iomem *baseAddr)
{
McASPTxReset(baseAddr);
/* Enable the FIFOs for DMA transfer */
McASPWriteFifoEnable(baseAddr + 0x1000, 1, 1);
/* Set I2S format in the transmitter/receiver format units */
McASPTxFmtI2SSet(baseAddr, WORD_SIZE, SLOT_SIZE,
MCASP_TX_MODE_DMA);
/* Configure the frame sync. I2S shall work in TDM format with 2 slots */
McASPTxFrameSyncCfg(baseAddr, 2, MCASP_TX_FS_WIDTH_WORD,
MCASP_TX_FS_INT_BEGIN_ON_FALL_EDGE);
/* configure the clock for transmitter */
McASPTxClkCfg(baseAddr, MCASP_TX_CLK_INTERNAL, 0, 0);
McASPTxClkPolaritySet(baseAddr, MCASP_TX_CLK_POL_FALL_EDGE);
McASPTxClkCheckConfig(baseAddr, MCASP_TX_CLKCHCK_DIV32,
0x00, 0xFF);
/* Enable synchronization of RX and TX sections */
McASPTxRxClkSyncEnable(baseAddr);
/* Enable the transmitter/receiver slots. I2S uses 2 slots */
McASPTxTimeSlotSet(baseAddr, I2S_SLOTS);
/*
** Set the serializers, Currently only one serializer is set as
** transmitter and one serializer as receiver.
*/
McASPSerializerTxSet(baseAddr, MCASP_XSER_TX);
/*
** Configure the McASP pins
** Input - Frame Sync, Clock and Serializer Rx
** Output - Serializer Tx is connected to the input of the codec
*/
McASPPinMcASPSet(baseAddr, 0xFFFFFFFF);
McASPPinDirOutputSet(baseAddr, MCASP_PIN_AXR(MCASP_XSER_TX)
| MCASP_PIN_ACLKX | MCASP_PIN_AFSX);
}
static void McASPI2SRxConfigure(volatile void __iomem *baseAddr)
{
McASPRxReset(baseAddr);
/* Enable the FIFOs for DMA transfer */
McASPReadFifoEnable(baseAddr + 0x1000, 1, 1);
/* Set I2S format in the transmitter/receiver format units */
McASPRxFmtI2SSet(baseAddr, WORD_SIZE, SLOT_SIZE,
MCASP_RX_MODE_DMA);
/* Configure the frame sync. I2S shall work in TDM format with 2 slots */
McASPRxFrameSyncCfg(baseAddr, 2, MCASP_RX_FS_WIDTH_WORD,
MCASP_RX_FS_INT_BEGIN_ON_FALL_EDGE);
/* configure the clock for receiver */
McASPRxClkCfg(baseAddr, MCASP_RX_CLK_EXTERNAL, 0, 0);
McASPRxClkPolaritySet(baseAddr, MCASP_RX_CLK_POL_FALL_EDGE);
McASPRxClkCheckConfig(baseAddr, MCASP_RX_CLKCHCK_DIV32,
0x00, 0xFF);
/* Enable synchronization of RX and TX sections */
McASPTxRxClkSyncEnable(baseAddr);
/* Enable the transmitter/receiver slots. I2S uses 2 slots */
McASPRxTimeSlotSet(baseAddr, I2S_SLOTS);
/*
** Set the serializers, Currently only one serializer is set as
** transmitter and one serializer as receiver.
*/
McASPSerializerRxSet(baseAddr, MCASP_XSER_RX);
/*
** Configure the McASP pins
** Input - Frame Sync, Clock and Serializer Rx
** Output - Serializer Tx is connected to the input of the codec
*/
McASPPinMcASPSet(baseAddr, 0xFFFFFFFF);
McASPPinDirInputSet(baseAddr, MCASP_PIN_AFSR
| MCASP_PIN_ACLKR
| MCASP_PIN_AXR(MCASP_XSER_RX));
}
/*
** Activates the data transmission/reception
** The DMA parameters shall be ready before calling this function.
*/
static void I2SDataTxActivate(volatile void __iomem *mcaspAddr,
volatile void __iomem *dmaAddr)
{
/* Start the clocks */
McASPTxClkStart(mcaspAddr, MCASP_TX_CLK_EXTERNAL);
/* Enable EDMA for the transfer */
EDMA3EnableTransfer(dmaAddr, EDMA3_CHA_MCASP1_TX,
EDMA3_TRIG_MODE_EVENT);
/* Activate the serializers */
//McASPRxSerActivate(mcaspAddr);
McASPTxSerActivate(mcaspAddr);
/* make sure that the XDATA bit is cleared to zero */
while(McASPTxStatusGet(mcaspAddr) & MCASP_TX_STAT_DATAREADY);
/* Activate the state machines */
McASPTxEnable(mcaspAddr);
}
/*
** Activates the data transmission/reception
** The DMA parameters shall be ready before calling this function.
*/
static void I2SDataRxActivate(volatile void __iomem *mcaspAddr,
volatile void __iomem *dmaAddr)
{
/* Start the clocks */
McASPRxClkStart(mcaspAddr, MCASP_RX_CLK_EXTERNAL);
/* Enable EDMA for the transfer */
EDMA3EnableTransfer(dmaAddr, EDMA3_CHA_MCASP1_RX,
EDMA3_TRIG_MODE_EVENT);
/* Activate the serializers */
McASPRxSerActivate(mcaspAddr);
/* Activate the state machines */
McASPRxEnable(mcaspAddr);
}
/*
** Activates the DMA transfer for a parameterset from the given buffer.
*/
static void BufferTxDMAActivate(volatile void __iomem *dmaAddr, unsigned int txBuf,
unsigned short numSamples, unsigned short parId, unsigned short linkPar)
{
EDMA3CCPaRAMEntry paramSet;
/* Copy the default paramset */
memcpy(¶mSet, &txDefaultPar, SIZE_PARAMSET - 2);
/* Enable completion interrupt */
paramSet.opt |= TX_DMA_INT_ENABLE;
paramSet.srcAddr = txBufPtr[txBuf];
paramSet.linkAddr = linkPar * SIZE_PARAMSET;
paramSet.bCnt = numSamples;
EDMA3SetPaRAM(dmaAddr, parId, ¶mSet);
}
/*
** Activates the DMA transfer for a parameter set from the given buffer.
*/
static void BufferRxDMAActivate(volatile void __iomem *dmaAddr, unsigned int rxBuf, unsigned short parId,
unsigned short parLink)
{
EDMA3CCPaRAMEntry paramSet;
/* Copy the default paramset */
memcpy(¶mSet, &rxDefaultPar, SIZE_PARAMSET - 2);
/* Enable completion interrupt */
paramSet.opt |= RX_DMA_INT_ENABLE;
paramSet.destAddr = rxBufPtr[rxBuf];
paramSet.bCnt = NUM_SAMPLES_PER_AUDIO_BUF;
paramSet.linkAddr = parLink * SIZE_PARAMSET ;
EDMA3SetPaRAM(dmaAddr, parId, ¶mSet);
}
/*
** This function will be called once receive DMA is completed
*/
static void McASPRxDMAComplHandler(void)
{
unsigned short nxtParToUpdate;
/*
** Update lastFullRxBuf to indicate a new buffer reception
** is completed.
*/
lastFullRxBuf = (lastFullRxBuf + 1) % NUM_BUF;
nxtParToUpdate = PAR_RX_START + parOffRcvd;
parOffRcvd = (parOffRcvd + 1) % NUM_PAR;
/*
** Update the DMA parameters for the received buffer to receive
** further data in proper buffer
*/
BufferRxDMAActivate(edma3ch_base, nxtBufToRcv, nxtParToUpdate,
PAR_RX_START + parOffRcvd);
/* update the next buffer to receive data */
nxtBufToRcv = (nxtBufToRcv + 1) % NUM_BUF;
}
/*
** This function will be called once transmit DMA is completed
*/
static void McASPTxDMAComplHandler(void)
{
ParamTxLoopJobSet(edma3ch_base, (unsigned short)(PAR_TX_START + parOffSent));
parOffSent = (parOffSent + 1) % NUM_PAR;
}
static irqreturn_t mcasp_irq_handler(int irq, void *data) {
printk("[kdj6724] %s(%d)\n", __FUNCTION__, __LINE__);
return IRQ_HANDLED;
}
//struct edma_info *prtd;
static int mcasp_irq_enable(void) {
int ret = -1;
//struct edma_info *prtd;
//prtd = kzalloc(sizeof(struct edma_info), GFP_KERNEL);
printk("[kdj6724] %s(%d)\n", __FUNCTION__, __LINE__);
//ret = request_irq(SYS_INT_EDMA, mcasp_irq_handler, IRQF_SHARED, "bd-edma", prtd);
printk("[kdj6724] %s(%d) ret:%d\n", __FUNCTION__, __LINE__, ret);
return 0;
}
static int audio_init(void)
{
ctrl_base = ioremap(SOC_CONTROL_REGS, SOC_CONTROL_SIZE);
McASP1PinMuxSetup(ctrl_base);
mcasp0_base = ioremap(SOC_MCASP_0_CFG, MCASP0_ADDR_SIZE);
mcasp1_base = ioremap(SOC_MCASP_1_CFG, MCASP1_ADDR_SIZE);
cmper_base = ioremap(SOC_CM_PER, CMPER_ADDR_SIZE);
edma3ch_base = ioremap(SOC_EDMA30CC_0_REGS, SOC_EDMA30CC_0_SIZE);
edma3ch0_base = ioremap(SOC_EDMA3CH_0_REG, SOC_EDMA3CH_SIZE);
edma3ch1_base = ioremap(SOC_EDMA3CH_1_REG, SOC_EDMA3CH_SIZE);
edma3ch2_base = ioremap(SOC_EDMA3CH_2_REG, SOC_EDMA3CH_SIZE);
McASPModuleClkConfig(cmper_base, CM_PER_MCASP1_CLKCTRL);
McASPModuleClkConfig(cmper_base, CM_PER_MCASP0_CLKCTRL);
EDMAModuleClkConfig(cmper_base, edma3ch0_base, edma3ch1_base, edma3ch2_base);
EDMA3Init(edma3ch_base, 0);
/* Request EDMA channels */
EDMA3RequestChannel(edma3ch_base, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_CHA_MCASP1_TX, EDMA3_CHA_MCASP1_TX, 0);
EDMA3RequestChannel(edma3ch_base, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_CHA_MCASP1_RX, EDMA3_CHA_MCASP1_RX, 0);
/* Initialize the DMA parameters */
I2SDMAParamInit(edma3ch_base);
/* Configure the McASP for I2S */
McASPI2SRxConfigure(mcasp0_base);
McASPI2STxConfigure(mcasp1_base);
I2SDataRxActivate(mcasp0_base, edma3ch_base);
I2SDataTxActivate(mcasp1_base, edma3ch_base);
return 0;
}
void hex_dump(unsigned int *buf, size_t len) {
size_t index=0;
if (buf == NULL || len <= 0) {
printk("[kdj6724] hex_dump error\n");
return;
}
printk("\n");
for (index=0; index<len; index++) {
if (index%16 == 0)
printk("\n");
else
printk("0x%04x ", buf[index]);
}
printk("\n");
}
int audio_run(void) {
unsigned short parToSend;
unsigned short parToLink;
unsigned int index = 0;
printk("Rx \n");
McASPRegDump(mcasp0_base);
printk("Tx\n");
printk("\n");
McASPRegDump(mcasp1_base);
printk("\n");
#if 0 // read
while(1) {
McASPRxDMAComplHandler();
while(McASPRxStatusGet(mcasp0_base) & MCASP_RX_STAT_DATAREADY);
hex_dump((void *)rxBufPtr[0], 32);
hex_dump((void *)rxBufPtr[1], 32);
hex_dump((void *)rxBufPtr[2], 32);
}
#endif
#if 1 // read RDATA reg.
printk("state: 0x%08x\n", McASPRxStatusGet(mcasp0_base));
#endif
return 0;
}
/*
* Open the device; in fact, there's nothing to do here.
*/
static int mcasp_open(struct inode *inode, struct file *filp) {
printk("[kdj6724] %s(%d)\n", __FUNCTION__, __LINE__);
//mcasp_irq_enable();
audio_init();
audio_run();
return 0;
}
/*
* Closing is just as simpler.
*/
static int mcasp_release(struct inode *inode, struct file *filp) {
printk("[kdj6724] %s(%d)\n", __FUNCTION__, __LINE__);
return 0;
}
static void mcasp_setup_cdev(struct cdev *dev, int minor,
struct file_operations *fops)
{
int err, devno = MKDEV(mcasp_major, minor);
cdev_init(dev, fops);
dev->owner = THIS_MODULE;
dev->ops = fops;
err = cdev_add (dev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk (KERN_NOTICE "Error %d adding simple%d", err, minor);
}
static struct file_operations mcasp_ops = {
.owner = THIS_MODULE,
.open = mcasp_open,
.release = mcasp_release,
};
#define MAX_MCASP_DEV 2
static struct cdev mcaspDev[MAX_MCASP_DEV];
#define EDMA_BINDING_LEGACY 0
#define EDMA_BINDING_TPCC 1
static const struct of_device_id edma_of_ids[] = {
{
.compatible = "ti,edma3",
.data = (void *)EDMA_BINDING_LEGACY,
},
{
.compatible = "ti,edma3-tpcc",
.data = (void *)EDMA_BINDING_TPCC,
},
{}
};
static int mcasp_audio_probe(struct platform_device *pdev) {
struct edma_soc_info *info = pdev->dev.platform_data;
struct mcasp_edma_cc *ecc;
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
char *irq_name;
struct resource *mem;
bool legacy_mode = true;
int ret = -1;
int irq;
if (node) {
const struct of_device_id *match;
match = of_match_node(edma_of_ids, node);
if (match && (u32)match->data == EDMA_BINDING_TPCC)
legacy_mode = false;
}
if (!pdev->dev.platform_data && !pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform data supplied\n");
return -EINVAL;
}
ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
if (!ecc) {
dev_err(dev, "Can't allocate controller\n");
return -ENOMEM;
}
ecc->dev = dev;
ecc->id = pdev->id;
mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma3_cc");
if (!mem) {
dev_dbg(dev, "mem resource not found, using index 0\n");
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(dev, "no mem resource?\n");
return -ENODEV;
}
}
//irq = platform_get_irq_byname(pdev, "edma3_ccint");
//irq_name = devm_kasprintf(dev, GFP_KERNEL, "bd-edma");
//ret = devm_request_irq(dev, SYS_INT_EDMA, mcasp_irq_handler, 0, irq_name, ecc);
return 0;
}
static int mcasp_audio_remove(struct platform_device *pdev) {
printk("[kdj6724] %s(%d)\n", __FUNCTION__, __LINE__);
return 0;
}
static struct platform_driver mcasp_edma_driver = {
.probe = mcasp_audio_probe,
.remove = mcasp_audio_remove,
.driver = {
.name = "mcasp-audio",
//.pm = &edma_pm_ops,
.of_match_table = edma_of_ids,
},
};
int __init init_mcasp_audio(void)
{
int result = 0;
printk("[kdj6724] %s(%d)\n", __FUNCTION__, __LINE__);
dev_t dev = MKDEV(mcasp_major, 0);
result = alloc_chrdev_region(&dev, 0, 2, "mcasp-audio");
mcasp_major = MAJOR(dev);
if (result < 0) {
printk(KERN_WARNING "unable to get major %d\n", mcasp_major);
return result;
}
if (mcasp_major == 0)
mcasp_major = result;
mcasp_setup_cdev(mcaspDev, 0, &mcasp_ops);
platform_driver_register(&mcasp_edma_driver);
return result;
}
void __exit exit_mcasp_audio(void)
{
iounmap(mcasp0_base);
iounmap(mcasp1_base);
iounmap(ctrl_base);
iounmap(cmper_base);
iounmap(edma3ch_base);
iounmap(edma3ch0_base);
iounmap(edma3ch1_base);
iounmap(edma3ch2_base);
//free_irq(SYS_INT_EDMA, prtd);
platform_driver_unregister(&mcasp_edma_driver);
}
module_init(init_mcasp_audio);
module_exit(exit_mcasp_audio);
MODULE_AUTHOR("kdj6724");
MODULE_DESCRIPTION("Bodyfriend MCASP Audio driver");
MODULE_LICENSE("GPL");
