Remove incomplete worker thread in alc5658
authorbsvt <b.theogaraj@samsung.com>
Wed, 13 Sep 2017 10:56:50 +0000 (03:56 -0700)
committerShivam Garg <garg.shivam@samsung.com>
Mon, 18 Sep 2017 14:03:32 +0000 (23:03 +0900)
os/drivers/audio/alc5658.c
os/drivers/audio/alc5658.h
os/include/tinyara/audio/i2s.h

index 7287351..8de592d 100644 (file)
  ****************************************************************************/
 
 #include <tinyara/config.h>
-
 #include <sys/types.h>
 #include <sys/ioctl.h>
-
 #include <stdint.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
 #include <fixedmath.h>
-#include <queue.h>
 #include <debug.h>
-
 #include <tinyara/irq.h>
 #include <tinyara/kmalloc.h>
 #include <tinyara/clock.h>
@@ -82,19 +78,20 @@ static const struct audio_ops_s g_audioops = {
 };
 
 /****************************************************************************
- * Private Functions
+ * Name: delay
+ *
+ * Description
+ *    Delay in ms.
  ****************************************************************************/
-
 static void delay(unsigned int mS)
 {
        volatile systime_t start = clock_systimer();
-
        mS = mS / MSEC_PER_TICK + 1;
 
-       while (1)
-               if ((start + mS) < clock_systimer()) {
+       while (1) {
+               if ((start + mS) < clock_systimer())
                        return;
-               }
+       }
 }
 
 /****************************************************************************
@@ -104,10 +101,6 @@ static void delay(unsigned int mS)
  *    Read the specified 16-bit register from the ALC5658 device.
  *
  ****************************************************************************/
-
-#if !defined(CONFIG_ALC5658_REGDUMP) && !defined(CONFIG_ALC5658_CLKDEBUG)
-static
-#endif
 uint16_t alc5658_readreg(FAR struct alc5658_dev_s *priv, uint16_t regaddr)
 {
 
@@ -144,7 +137,6 @@ uint16_t alc5658_readreg(FAR struct alc5658_dev_s *priv, uint16_t regaddr)
  *   Write the specified 16-bit register to the ALC5658 device.
  *
  ************************************************************************************/
-
 static void alc5658_writereg(FAR struct alc5658_dev_s *priv, uint16_t regaddr, uint16_t regval)
 {
        int32_t ret;
@@ -167,6 +159,13 @@ static void alc5658_writereg(FAR struct alc5658_dev_s *priv, uint16_t regaddr, u
        return;
 }
 
+/************************************************************************************
+ * Name: alc5658_modifyreg
+ *
+ * Description:
+ *   Modify the specified 16-bit register to the ALC5658 device.
+ *
+ ************************************************************************************/
 static uint16_t alc5658_modifyreg(FAR struct alc5658_dev_s *priv, uint16_t regaddr, uint16_t set, uint16_t clear)
 {
        uint16_t data;
@@ -179,6 +178,13 @@ static uint16_t alc5658_modifyreg(FAR struct alc5658_dev_s *priv, uint16_t regad
        return alc5658_readreg(priv, regaddr);
 }
 
+/************************************************************************************
+ * Name: alc5658_exec_i2c_script
+ *
+ * Description:
+ *   Executes given script through i2c to configuure ALC5658 device.
+ *
+ ************************************************************************************/
 static void alc5658_exec_i2c_script(FAR struct alc5658_dev_s *priv, t_codec_init_script_entry *script, uint32_t size)
 {
        uint32_t i;
@@ -198,7 +204,6 @@ static void alc5658_exec_i2c_script(FAR struct alc5658_dev_s *priv, t_codec_init
  *  by a signal.
  *
  ************************************************************************************/
-
 static void alc5658_takesem(sem_t *sem)
 {
        int ret;
@@ -217,7 +222,6 @@ static void alc5658_takesem(sem_t *sem)
  *   volume and balance settings.
  *
  ************************************************************************************/
-
 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
 static inline uint16_t alc5658_scalevolume(uint16_t volume, b16_t scale)
 {
@@ -233,19 +237,18 @@ static inline uint16_t alc5658_scalevolume(uint16_t volume, b16_t scale)
  *   volume and balance settings.
  *
  ************************************************************************************/
-
 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
 static void alc5658_setvolume(FAR struct alc5658_dev_s *priv, uint16_t volume, bool mute)
 {
 
-       audvdbg("volume=%u mute=%u\n", volume, mute);
-
+       audvdbg(" alc5658_setvolume volume=%u mute=%u\n", volume, mute);
        /* ADD VOLUME CODE HERE */
 
        /* Remember the volume level and mute settings */
-
+       alc5658_takesem(&priv->devsem);
        priv->volume = volume;
        priv->mute = mute;
+       alc5658_givesem(&priv->devsem);
 }
 #endif                                                 /* CONFIG_AUDIO_EXCLUDE_VOLUME */
 
@@ -258,7 +261,6 @@ static void alc5658_setvolume(FAR struct alc5658_dev_s *priv, uint16_t volume, b
  *   The level and range are in whole percentage levels (0-100).
  *
  ************************************************************************************/
-
 #ifndef CONFIG_AUDIO_EXCLUDE_TONE
 static void alc5658_setbass(FAR struct alc5658_dev_s *priv, uint8_t bass)
 {
@@ -275,7 +277,6 @@ static void alc5658_setbass(FAR struct alc5658_dev_s *priv, uint8_t bass)
  *   The level and range are in whole percentage levels (0-100).
  *
  ************************************************************************************/
-
 #ifndef CONFIG_AUDIO_EXCLUDE_TONE
 static void alc5658_settreble(FAR struct alc5658_dev_s *priv, uint8_t treble)
 {
@@ -284,27 +285,32 @@ static void alc5658_settreble(FAR struct alc5658_dev_s *priv, uint8_t treble)
 #endif                                                 /* CONFIG_AUDIO_EXCLUDE_TONE */
 
 /****************************************************************************
- * Name: alc5658_setdatawidth
+ * Name: alc5658_set_i2s_datawidth
  *
  * Description:
  *   Set the 8- 16- 24- bit data modes
  *
  ****************************************************************************/
-
-static void alc5658_setdatawidth(FAR struct alc5658_dev_s *priv)
+static void alc5658_set_i2s_datawidth(FAR struct alc5658_dev_s *priv)
 {
+       if (priv->inout)
+               I2S_RXDATAWIDTH(priv->i2s, priv->bpsamp);
+       else
+               I2S_TXDATAWIDTH(priv->i2s, priv->bpsamp);
 }
 
 /****************************************************************************
- * Name: alc5658_setbitrate
+ * Name: alc5658_set_i2s_samplerate
  *
  * Description:
  *
  ****************************************************************************/
-
-static void alc5658_setbitrate(FAR struct alc5658_dev_s *priv)
+static void alc5658_set_i2s_samplerate(FAR struct alc5658_dev_s *priv)
 {
-
+       if (priv->inout)
+               I2S_RXSAMPLERATE(priv->i2s, priv->samprate);
+       else
+               I2S_TXSAMPLERATE(priv->i2s, priv->samprate);
 }
 
 /****************************************************************************
@@ -314,7 +320,6 @@ static void alc5658_setbitrate(FAR struct alc5658_dev_s *priv)
  *   Get the audio device capabilities
  *
  ****************************************************************************/
-
 static int alc5658_getcaps(FAR struct audio_lowerhalf_s *dev, int type, FAR struct audio_caps_s *caps)
 {
        /* Validate the structure */
@@ -345,8 +350,7 @@ static int alc5658_getcaps(FAR struct audio_lowerhalf_s *dev, int type, FAR stru
                         */
 
                        /* The types of audio units we implement */
-
-                       caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE | AUDIO_TYPE_PROCESSING;
+                       caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE | AUDIO_TYPE_PROCESSING;
 
                        break;
 
@@ -461,7 +465,6 @@ static int alc5658_getcaps(FAR struct audio_lowerhalf_s *dev, int type, FAR stru
  *   Configure the audio device for the specified  mode of operation.
  *
  ****************************************************************************/
-
 #ifdef CONFIG_AUDIO_MULTI_SESSION
 static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR void *session, FAR const struct audio_caps_s *caps)
 #else
@@ -476,14 +479,14 @@ static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR const struct
        DEBUGASSERT(priv && caps);
        audvdbg("ac_type: %d\n", caps->ac_type);
 
-       /* Process the configure operation */
+       /* ALC5658 supports on the fly changes for almost all changes
+       so no need to do anything. But if any issue, worth looking here */
 
        switch (caps->ac_type) {
        case AUDIO_TYPE_FEATURE:
                audvdbg("  AUDIO_TYPE_FEATURE\n");
 
-               /* Process based on Feature Unit */
-
+               /* Inner swich case: Process based on Feature Unit */
                switch (caps->ac_format.hw) {
 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
                case AUDIO_FU_VOLUME: {
@@ -504,52 +507,71 @@ static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR const struct
 #endif                                                 /* CONFIG_AUDIO_EXCLUDE_VOLUME */
 
 #ifndef CONFIG_AUDIO_EXCLUDE_TONE
-               case AUDIO_FU_BASS: {
-                       /* Set the bass.  The percentage level (0-100) is in the
-                        * ac_controls.b[0] parameter.
-                        */
+               case AUDIO_FU_BASS:
+               {       /* Set the bass.  The percentage level (0-100) is in the
+                        * ac_controls.b[0] parameter. */
 
                        uint8_t bass = caps->ac_controls.b[0];
                        audvdbg("    Bass: %d\n", bass);
-
-                       if (bass <= 100) {
+                       if (bass <= 100)
                                alc5658_setbass(priv, bass);
-                       } else {
-                               ret = -EDOM;
-                       }
                }
                break;
-
-               case AUDIO_FU_TREBLE: {
-                       /* Set the treble.  The percentage level (0-100) is in the
-                        * ac_controls.b[0] parameter.
-                        */
+               case AUDIO_FU_TREBLE:
+               {       /* Set the treble.  The percentage level (0-100) is in the
+                        * ac_controls.b[0] parameter. */
 
                        uint8_t treble = caps->ac_controls.b[0];
                        audvdbg("    Treble: %d\n", treble);
-
-                       if (treble <= 100) {
+                       if (treble <= 100)
                                alc5658_settreble(priv, treble);
-                       } else {
-                               ret = -EDOM;
-                       }
                }
                break;
 #endif                                                 /* CONFIG_AUDIO_EXCLUDE_TONE */
-
                default:
                        auddbg("    ERROR: Unrecognized feature unit\n");
-                       ret = -ENOTTY;
                        break;
                }
-               break;
+               break; /* Break for inner switch case */
+       case AUDIO_TYPE_INPUT: {
+               audvdbg("  AUDIO_TYPE_OUTPUT:\n");
+               /* Verify that all of the requested values are supported */
+
+               ret = -ERANGE;
+               if (caps->ac_channels != 1 && caps->ac_channels != 2) {
+                       auddbg("ERROR: Unsupported number of channels: %d\n", caps->ac_channels);
+                       break;
+               }
 
+               if (caps->ac_controls.b[2] != 8 && caps->ac_controls.b[2] != 16) {
+                       auddbg("ERROR: Unsupported bits per sample: %d\n", caps->ac_controls.b[2]);
+                       break;
+               }
+
+               /* Save the current stream configuration */
+
+               priv->samprate = caps->ac_controls.hw[0];
+               priv->nchannels = caps->ac_channels;
+               priv->bpsamp = caps->ac_controls.b[2];
+
+               audvdbg("    Number of channels: 0x%x\n", priv->nchannels);
+               audvdbg("    Sample rate:        0x%x\n", priv->samprate);
+               audvdbg("    Sample width:       0x%x\n", priv->bpsamp);
+
+               /* Reconfigure the FLL to support the resulting number or channels,
+                * bits per sample, and bitrate.
+                */
+#if 0
+               alc5658_set_i2s_datawidth(priv);
+               alc5658_set_i2s_samplerate(priv);
+
+               alc5658_clock_analysis(&priv->dev, "AUDIO_TYPE_OUTPUT");
+#endif
+               priv->inout = true;
+               ret = OK;
+       }
        case AUDIO_TYPE_OUTPUT: {
                audvdbg("  AUDIO_TYPE_OUTPUT:\n");
-               audvdbg("    Number of channels: %u\n", caps->ac_channels);
-               audvdbg("    Sample rate:        %u\n", caps->ac_controls.hw[0]);
-               audvdbg("    Sample width:       %u\n", caps->ac_controls.b[2]);
-
                /* Verify that all of the requested values are supported */
 
                ret = -ERANGE;
@@ -569,15 +591,21 @@ static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR const struct
                priv->nchannels = caps->ac_channels;
                priv->bpsamp = caps->ac_controls.b[2];
 
+               audvdbg("    Number of channels: 0x%x\n", priv->nchannels);
+               audvdbg("    Sample rate:        0x%x\n", priv->samprate);
+               audvdbg("    Sample width:       0x%x\n", priv->bpsamp);
+
                /* Reconfigure the FLL to support the resulting number or channels,
                 * bits per sample, and bitrate.
                 */
-
-               alc5658_setdatawidth(priv);
-               alc5658_setbitrate(priv);
+#if 0
+               alc5658_set_i2s_datawidth(priv);
+               alc5658_set_i2s_samplerate(priv);
 
                alc5658_clock_analysis(&priv->dev, "AUDIO_TYPE_OUTPUT");
+#endif
                ret = OK;
+               priv->inout = false;
        }
        break;
 
@@ -595,7 +623,6 @@ static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR const struct
  *   Shutdown the ALC5658 chip and put it in the lowest power state possible.
  *
  ****************************************************************************/
-
 static int alc5658_shutdown(FAR struct audio_lowerhalf_s *dev)
 {
        FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)dev;
@@ -615,209 +642,6 @@ static int alc5658_shutdown(FAR struct audio_lowerhalf_s *dev)
 }
 
 /****************************************************************************
- * Name: alc5658_senddone
- *
- * Description:
- *   This is the I2S callback function that is invoked when the transfer
- *   completes.
- *
- ****************************************************************************/
-
-static void alc5658_senddone(FAR struct i2s_dev_s *i2s, FAR struct ap_buffer_s *apb, FAR void *arg, int result)
-{
-       FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)arg;
-       struct audio_msg_s msg;
-       irqstate_t flags;
-       int ret;
-
-       DEBUGASSERT(i2s && priv && priv->running && apb);
-       audvdbg("apb=%p inflight=%d result=%d\n", apb, priv->inflight, result);
-
-       /* We do not place any restriction on the context in which this function
-        * is called.  It may be called from an interrupt handler.  Therefore, the
-        * doneq and in-flight values might be accessed from the interrupt level.
-        * Not the best design.  But we will use interrupt controls to protect
-        * against that possibility.
-        */
-
-       flags = irqsave();
-
-       /* Add the completed buffer to the end of our doneq.  We do not yet
-        * decrement the reference count.
-        */
-
-       dq_addlast((FAR dq_entry_t *) apb, &priv->doneq);
-
-       /* And decrement the number of buffers in-flight */
-
-       DEBUGASSERT(priv->inflight > 0);
-       priv->inflight--;
-
-       /* Save the result of the transfer */
-       /* REVISIT:  This can be overwritten */
-
-       priv->result = result;
-       irqrestore(flags);
-
-       /* Now send a message to the worker thread, informing it that there are
-        * buffers in the done queue that need to be cleaned up.
-        */
-
-       msg.msgId = AUDIO_MSG_COMPLETE;
-       ret = mq_send(priv->mq, (FAR const char *)&msg, sizeof(msg), CONFIG_ALC5658_MSG_PRIO);
-       if (ret < 0) {
-               auddbg("ERROR: mq_send failed: %d\n", errno);
-       }
-}
-
-/****************************************************************************
- * Name: alc5658_returnbuffers
- *
- * Description:
- *   This function is called after the complete of one or more data
- *   transfers.  This function will empty the done queue and release our
- *   reference to each buffer.
- *
- ****************************************************************************/
-
-static void alc5658_returnbuffers(FAR struct alc5658_dev_s *priv)
-{
-       FAR struct ap_buffer_s *apb;
-       irqstate_t flags;
-
-       /* The doneq and in-flight values might be accessed from the interrupt
-        * level in some implementations.  Not the best design.  But we will
-        * use interrupt controls to protect against that possibility.
-        */
-
-       flags = irqsave();
-       while (dq_peek(&priv->doneq) != NULL) {
-               /* Take the next buffer from the queue of completed transfers */
-
-               apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->doneq);
-               irqrestore(flags);
-
-               audvdbg("Returning: apb=%p curbyte=%d nbytes=%d flags=%04x\n", apb, apb->curbyte, apb->nbytes, apb->flags);
-
-               /* Are we returning the final buffer in the stream? */
-
-               if ((apb->flags & AUDIO_APB_FINAL) != 0) {
-                       /* Both the pending and the done queues should be empty and there
-                        * should be no buffers in-flight.
-                        */
-
-                       DEBUGASSERT(dq_empty(&priv->doneq) && dq_empty(&priv->pendq) && priv->inflight == 0);
-
-                       /* Set the terminating flag.  This will, eventually, cause the
-                        * worker thread to exit (if it is not already terminating).
-                        */
-
-                       audvdbg("Terminating\n");
-                       priv->terminating = true;
-               }
-
-               /* Release our reference to the audio buffer */
-
-               apb_free(apb);
-
-               /* Send the buffer back up to the previous level. */
-
-#ifdef CONFIG_AUDIO_MULTI_SESSION
-               priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK, NULL);
-#else
-               priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
-#endif
-               flags = irqsave();
-       }
-
-       irqrestore(flags);
-}
-
-/****************************************************************************
- * Name: alc5658_sendbuffer
- *
- * Description:
- *   Start the transfer an audio buffer to the ALC5658 via I2S.  This
- *   will not wait for the transfer to complete but will return immediately.
- *   the alc5658 called will be invoked when the transfer
- *   completes, stimulating the worker thread to call this function again.
- *
- ****************************************************************************/
-
-static int alc5658_sendbuffer(FAR struct alc5658_dev_s *priv)
-{
-       FAR struct ap_buffer_s *apb;
-       irqstate_t flags;
-       uint32_t timeout;
-       int shift;
-       int ret = OK;
-
-       /* Loop while there are audio buffers to be sent and we have few than
-        * CONFIG_ALC5658_INFLIGHT then "in-flight"
-        *
-        * The 'inflight' value might be modified from the interrupt level in some
-        * implementations.  We will use interrupt controls to protect against
-        * that possibility.
-        *
-        * The 'pendq', on the other hand, is protected via a semaphore.  Let's
-        * hold the semaphore while we are busy here and disable the interrupts
-        * only while accessing 'inflight'.
-        */
-
-       alc5658_takesem(&priv->pendsem);
-       while (priv->inflight < CONFIG_ALC5658_INFLIGHT && dq_peek(&priv->pendq) != NULL && !priv->paused) {
-               /* Take next buffer from the queue of pending transfers */
-
-               apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq);
-               audvdbg("Sending apb=%p, size=%d inflight=%d\n", apb, apb->nbytes, priv->inflight);
-
-               /* Increment the number of buffers in-flight before sending in order
-                * to avoid a possible race condition.
-                */
-
-               flags = irqsave();
-               priv->inflight++;
-               irqrestore(flags);
-
-               /* Send the entire audio buffer via I2S.  What is a reasonable timeout
-                * to use?  This would depend on the bit rate and size of the buffer.
-                *
-                * Samples in the buffer (samples):
-                *   = buffer_size * 8 / bpsamp                           samples
-                * Sample rate (samples/second):
-                *   = samplerate * nchannels
-                * Expected transfer time (seconds):
-                *   = (buffer_size * 8) / bpsamp / samplerate / nchannels
-                *
-                * We will set the timeout about twice that.
-                *
-                * NOTES:
-                * - The multiplier of 8 becomes 16000 for 2x and units of
-                *   milliseconds.
-                * - 16000 is a approximately 16384 (1 << 14), bpsamp is either
-                *   (1 << 3) or (1 << 4), and nchannels is either (1 << 0) or
-                *   (1 << 1).  So this can be simplifies to (milliseconds):
-                *
-                *   = (buffer_size << shift) / samplerate
-                */
-
-               shift = (priv->bpsamp == 8) ? 14 - 3 : 14 - 4;
-               shift -= (priv->nchannels > 1) ? 1 : 0;
-
-               timeout = MSEC2TICK(((uint32_t)(apb->nbytes - apb->curbyte) << shift) / (uint32_t) priv->samprate);
-
-               ret = I2S_SEND(priv->i2s, apb, alc5658_senddone, priv, timeout);
-               if (ret < 0) {
-                       auddbg("ERROR: I2S_SEND failed: %d\n", ret);
-                       break;
-               }
-       }
-
-       alc5658_givesem(&priv->pendsem);
-       return ret;
-}
-
-/****************************************************************************
  * Name: alc5658_start
  *
  * Description:
@@ -831,59 +655,31 @@ static int alc5658_start(FAR struct audio_lowerhalf_s *dev, FAR void *session)
 static int alc5658_start(FAR struct audio_lowerhalf_s *dev)
 #endif
 {
+       audvdbg(" alc5658_start Entry\n");
        FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)dev;
-       struct sched_param sparam;
-       struct mq_attr attr;
-       pthread_attr_t tattr;
-       FAR void *value;
-       int ret;
-
-       audvdbg("Entry\n");
 
+       if (priv->running)
+               return OK;
+       
+       /* Fix me -- Need to support multiple samplerate */
+       alc5658_exec_i2c_script(priv, codec_init_pll_16K, sizeof(codec_init_pll_16K) / sizeof(t_codec_init_script_entry));
+       alc5658_exec_i2c_script(priv, codec_init_inout_script2, sizeof(codec_init_inout_script2) / sizeof(t_codec_init_script_entry));
+       
+       priv->running = 1;
+       
+       dq_entry_t *tmp = NULL;
+       dq_queue_t * q = &priv->pendq;
+       
+       alc5658_takesem(&priv->devsem);
+       for (tmp = dq_peek(q); tmp; tmp = dq_next(tmp)) {
+               alc5658_enqueuebuffer(dev, (struct ap_buffer_s *) tmp);
+       }
+       alc5658_givesem(&priv->devsem);
+       
        /* Exit reduced power modes of operation */
        /* REVISIT */
 
-       /* Create a message queue for the worker thread */
-
-       snprintf(priv->mqname, sizeof(priv->mqname), "/tmp/%X", priv);
-
-       attr.mq_maxmsg = 16;
-       attr.mq_msgsize = sizeof(struct audio_msg_s);
-       attr.mq_curmsgs = 0;
-       attr.mq_flags = 0;
-
-       priv->mq = mq_open(priv->mqname, O_RDWR | O_CREAT, 0644, &attr);
-       if (priv->mq == NULL) {
-               /* Error creating message queue! */
-
-               auddbg("ERROR: Couldn't allocate message queue\n");
-               return -ENOMEM;
-       }
-
-       /* Join any old worker thread we had created to prevent a memory leak */
-
-       if (priv->threadid != 0) {
-               audvdbg("Joining old thread\n");
-               pthread_join(priv->threadid, &value);
-       }
-
-       /* Start our thread for sending data to the device */
-
-       pthread_attr_init(&tattr);
-       sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 3;
-       (void)pthread_attr_setschedparam(&tattr, &sparam);
-       (void)pthread_attr_setstacksize(&tattr, CONFIG_ALC5658_WORKER_STACKSIZE);
-
-       audvdbg("Starting worker thread\n");
-       ret = pthread_create(&priv->threadid, &tattr, alc5658_workerthread, (pthread_addr_t) priv);
-       if (ret != OK) {
-               auddbg("ERROR: pthread_create failed: %d\n", ret);
-       } else {
-               pthread_setname_np(priv->threadid, "alc5658");
-               audvdbg("Created worker thread\n");
-       }
-
-       return ret;
+       return OK; /* Fix this -- always returns OK */
 }
 
 /****************************************************************************
@@ -902,19 +698,9 @@ static int alc5658_stop(FAR struct audio_lowerhalf_s *dev)
 #endif
 {
        FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)dev;
-       struct audio_msg_s term_msg;
-       FAR void *value;
-
-       /* Send a message to stop all audio streaming */
 
-       term_msg.msgId = AUDIO_MSG_STOP;
-       term_msg.u.data = 0;
-       mq_send(priv->mq, (FAR const char *)&term_msg, sizeof(term_msg), CONFIG_ALC5658_MSG_PRIO);
-
-       /* Join the worker thread */
-
-       pthread_join(priv->threadid, &value);
-       priv->threadid = 0;
+       /* Need to run the stop script here */
+       alc5658_exec_i2c_script(priv, codec_stop_script, sizeof(codec_stop_script) / sizeof(t_codec_init_script_entry));
 
        /* Enter into a reduced power usage mode */
        /* REVISIT: */
@@ -929,7 +715,6 @@ static int alc5658_stop(FAR struct audio_lowerhalf_s *dev)
  * Description: Pauses the playback.
  *
  ****************************************************************************/
-
 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
 #ifdef CONFIG_AUDIO_MULTI_SESSION
 static int alc5658_pause(FAR struct audio_lowerhalf_s *dev, FAR void *session)
@@ -944,10 +729,10 @@ static int alc5658_pause(FAR struct audio_lowerhalf_s *dev)
 
                priv->paused = true;
                alc5658_setvolume(priv, priv->volume, true);
-               ALC5658_DISABLE(priv->lower);
+               ALC5658_DISABLE(priv->lower); /* Need inputs from REALTEK */
        }
 
-       return OK;
+return OK;
 }
 #endif                                                 /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
 
@@ -957,7 +742,6 @@ static int alc5658_pause(FAR struct audio_lowerhalf_s *dev)
  * Description: Resumes the playback.
  *
  ****************************************************************************/
-
 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
 #ifdef CONFIG_AUDIO_MULTI_SESSION
 static int alc5658_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
@@ -972,8 +756,7 @@ static int alc5658_resume(FAR struct audio_lowerhalf_s *dev)
                alc5658_setvolume(priv, priv->volume, false);
 
                /* Enable interrupts to allow sampling data */
-
-               alc5658_sendbuffer(priv);
+               /* Need resume logic later. Need to know if alc5658 dma can be paused and resumed */
 #ifdef ALC5658_USE_FFLOCK_INT
                ALC5658_ENABLE(priv->lower);
 #endif
@@ -984,51 +767,67 @@ static int alc5658_resume(FAR struct audio_lowerhalf_s *dev)
 #endif                                                 /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
 
 /****************************************************************************
+ * Name: alc5658_rxcallback
+ *
+ * Description: Called when I2S filled a buffer. No recycling mechanism now.
+ *
+ ****************************************************************************/
+
+static void alc5658_rxtxcallback(FAR struct i2s_dev_s *dev, FAR struct ap_buffer_s *apb, FAR void *arg, int result)
+{
+       FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)arg;
+
+       DEBUGASSERT(priv &&  apb);
+       audvdbg("alc5658_rxcallback, devaddr= 0x%x, apbaddr  =0x%x\n", dev, apb);
+       
+       /* Call upper callback, let it post msg to user q */
+       priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
+
+       alc5658_takesem(&priv->devsem);
+       
+       dq_entry_t *tmp;
+       for (tmp = (dq_entry_t*)dq_peek(&priv->pendq); tmp; tmp = dq_next(tmp)) {
+               if (tmp == (dq_entry_t*)apb) {
+                       dq_rem(tmp, &priv->pendq);
+                       audvdbg("found the apb to remove 0x%x\n", tmp);
+                       break;
+               }
+       }
+
+       alc5658_givesem(&priv->devsem);
+}
+
+/****************************************************************************
  * Name: alc5658_enqueuebuffer
  *
  * Description: Enqueue an Audio Pipeline Buffer for playback/ processing.
  *
  ****************************************************************************/
-
 static int alc5658_enqueuebuffer(FAR struct audio_lowerhalf_s *dev, FAR struct ap_buffer_s *apb)
 {
        FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)dev;
-       struct audio_msg_s term_msg;
        int ret;
 
-       audvdbg("Enqueueing: apb=%p curbyte=%d nbytes=%d flags=%04x\n", apb, apb->curbyte, apb->nbytes, apb->flags);
-
-       /* Take a reference on the new audio buffer */
-
-       apb_reference(apb);
-
-       /* Add the new buffer to the tail of pending audio buffers */
-
-       alc5658_takesem(&priv->pendsem);
-       apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
-       dq_addlast(&apb->dq_entry, &priv->pendq);
-       alc5658_givesem(&priv->pendsem);
+       audvdbg("alc5658_enqueuebuffer: apbadr = 0x%x\n", apb);
 
-       /* Send a message to the worker thread indicating that a new buffer has been
-        * enqueued.  If mq is NULL, then the playing has not yet started.  In that
-        * case we are just "priming the pump" and we don't need to send any message.
-        */
-
-       ret = OK;
-       if (priv->mq != NULL) {
-               term_msg.msgId = AUDIO_MSG_ENQUEUE;
-               term_msg.u.data = 0;
-
-               ret = mq_send(priv->mq, (FAR const char *)&term_msg, sizeof(term_msg), CONFIG_ALC5658_MSG_PRIO);
-               if (ret < 0) {
-                       int errcode = errno;
-                       DEBUGASSERT(errcode > 0);
+       /* Need to fix later */
+       if (!priv->running) {
+               apb_reference(apb);
 
-                       auddbg("ERROR: mq_send failed: %d\n", errcode);
-                       UNUSED(errcode);
-               }
+               /* Add the new buffer to the tail of pending audio buffers */
+               alc5658_takesem(&priv->devsem);
+               dq_addlast(&apb->dq_entry, &priv->pendq);
+               alc5658_givesem(&priv->devsem);
+               return OK;
        }
-
+       
+       if (priv->inout) /* record */
+       ret = I2S_RECEIVE(priv->i2s, apb, alc5658_rxtxcallback, priv, 0);
+       else                    /* playback */
+       ret = I2S_SEND(priv->i2s, apb, alc5658_rxtxcallback, priv, 0);
+
+       audvdbg("I2s  returned 0x%x\n", ret);
+       
        return ret;
 }
 
@@ -1038,10 +837,10 @@ static int alc5658_enqueuebuffer(FAR struct audio_lowerhalf_s *dev, FAR struct a
  * Description: Called when an enqueued buffer is being cancelled.
  *
  ****************************************************************************/
-
 static int alc5658_cancelbuffer(FAR struct audio_lowerhalf_s *dev, FAR struct ap_buffer_s *apb)
 {
        audvdbg("apb=%p\n", apb);
+       /* Need to add logic here */
        return OK;
 }
 
@@ -1051,7 +850,6 @@ static int alc5658_cancelbuffer(FAR struct audio_lowerhalf_s *dev, FAR struct ap
  * Description: Perform a device ioctl
  *
  ****************************************************************************/
-
 static int alc5658_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd, unsigned long arg)
 {
 #ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
@@ -1101,7 +899,6 @@ static int alc5658_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd, unsigned lo
  * Description: Reserves a session (the only one we have).
  *
  ****************************************************************************/
-
 #ifdef CONFIG_AUDIO_MULTI_SESSION
 static int alc5658_reserve(FAR struct audio_lowerhalf_s *dev, FAR void **session)
 #else
@@ -1113,7 +910,7 @@ static int alc5658_reserve(FAR struct audio_lowerhalf_s *dev)
 
        /* Borrow the APBQ semaphore for thread sync */
 
-       alc5658_takesem(&priv->pendsem);
+       alc5658_takesem(&priv->devsem);
        if (priv->reserved) {
                ret = -EBUSY;
        } else {
@@ -1131,7 +928,7 @@ static int alc5658_reserve(FAR struct audio_lowerhalf_s *dev)
                priv->reserved = true;
        }
 
-       alc5658_givesem(&priv->pendsem);
+       alc5658_givesem(&priv->devsem);
 
        return ret;
 }
@@ -1142,7 +939,6 @@ static int alc5658_reserve(FAR struct audio_lowerhalf_s *dev)
  * Description: Releases the session (the only one we have).
  *
  ****************************************************************************/
-
 #ifdef CONFIG_AUDIO_MULTI_SESSION
 static int alc5658_release(FAR struct audio_lowerhalf_s *dev, FAR void *session)
 #else
@@ -1150,23 +946,10 @@ static int alc5658_release(FAR struct audio_lowerhalf_s *dev)
 #endif
 {
        FAR struct alc5658_dev_s *priv = (FAR struct alc5658_dev_s *)dev;
-       void *value;
-
-       /* Join any old worker thread we had created to prevent a memory leak */
-
-       if (priv->threadid != 0) {
-               pthread_join(priv->threadid, &value);
-               priv->threadid = 0;
-       }
-
-       /* Borrow the APBQ semaphore for thread sync */
-
-       alc5658_takesem(&priv->pendsem);
-
-       /* Really we should free any queued buffers here */
 
+       alc5658_takesem(&priv->devsem);
        priv->reserved = false;
-       alc5658_givesem(&priv->pendsem);
+       alc5658_givesem(&priv->devsem);
 
        return OK;
 }
@@ -1183,7 +966,6 @@ static int alc5658_release(FAR struct audio_lowerhalf_s *dev)
  *   ALC5658 interrupts were disabled in the interrupt handler.
  *
  ****************************************************************************/
-
 #ifdef ALC5658_USE_FFLOCK_INT
 static void alc5658_interrupt_work(FAR void *arg)
 {
@@ -1264,157 +1046,6 @@ static int alc5658_interrupt(FAR const struct alc5658_lower_s *lower, FAR void *
 #endif
 
 /****************************************************************************
- * Name: alc5658_workerthread
- *
- *  This is the thread that feeds data to the chip and keeps the audio
- *  stream going.
- *
- ****************************************************************************/
-
-static void *alc5658_workerthread(pthread_addr_t pvarg)
-{
-       FAR struct alc5658_dev_s *priv = (struct alc5658_dev_s *)pvarg;
-       struct audio_msg_s msg;
-       FAR struct ap_buffer_s *apb;
-       int msglen;
-       int prio;
-
-       audvdbg("Entry\n");
-
-#ifndef CONFIG_AUDIO_EXCLUDE_STOP
-       priv->terminating = false;
-#endif
-
-       /* Mark ourself as running and make sure that ALC5658 interrupts are
-        * enabled.
-        */
-
-       priv->running = true;
-#ifdef ALC5658_USE_FFLOCK_INT
-       ALC5658_ENABLE(priv->lower);
-#endif
-       alc5658_setvolume(priv, priv->volume, false);
-
-       /* Loop as long as we are supposed to be running and as long as we have
-        * buffers in-flight.
-        */
-
-       while (priv->running || priv->inflight > 0) {
-               /* Check if we have been asked to terminate.  We have to check if we
-                * still have buffers in-flight.  If we do, then we can't stop until
-                * birds come back to roost.
-                */
-
-               if (priv->terminating && priv->inflight <= 0) {
-                       /* We are IDLE.  Break out of the loop and exit. */
-
-                       break;
-               } else {
-                       /* Check if we can send more audio buffers to the ALC5658 */
-
-                       alc5658_sendbuffer(priv);
-               }
-
-               /* Wait for messages from our message queue */
-
-               msglen = mq_receive(priv->mq, (FAR char *)&msg, sizeof(msg), &prio);
-
-               /* Handle the case when we return with no message */
-
-               if (msglen < sizeof(struct audio_msg_s)) {
-                       auddbg("ERROR: Message too small: %d\n", msglen);
-                       continue;
-               }
-
-               /* Process the message */
-
-               switch (msg.msgId) {
-               /* The ISR has requested more data.  We will catch this case at
-                * the top of the loop.
-                */
-
-               case AUDIO_MSG_DATA_REQUEST:
-                       audvdbg("AUDIO_MSG_DATA_REQUEST\n");
-                       break;
-
-                       /* Stop the playback */
-
-#ifndef CONFIG_AUDIO_EXCLUDE_STOP
-               case AUDIO_MSG_STOP:
-                       /* Indicate that we are terminating */
-
-                       audvdbg("AUDIO_MSG_STOP: Terminating\n");
-                       priv->terminating = true;
-                       break;
-#endif
-
-               /* We have a new buffer to send.  We will catch this case at
-                * the top of the loop.
-                */
-
-               case AUDIO_MSG_ENQUEUE:
-                       audvdbg("AUDIO_MSG_ENQUEUE\n");
-                       break;
-
-               /* We will wake up from the I2S callback with this message */
-
-               case AUDIO_MSG_COMPLETE:
-                       audvdbg("AUDIO_MSG_COMPLETE\n");
-                       alc5658_returnbuffers(priv);
-                       break;
-
-               default:
-                       auddbg("ERROR: Ignoring message ID %d\n", msg.msgId);
-                       break;
-               }
-       }
-
-       /* Reset the ALC5658 hardware */
-
-       alc5658_hw_reset(priv);
-
-       /* Return any pending buffers in our pending queue */
-
-       alc5658_takesem(&priv->pendsem);
-       while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL) {
-               /* Release our reference to the buffer */
-
-               apb_free(apb);
-
-               /* Send the buffer back up to the previous level. */
-
-#ifdef CONFIG_AUDIO_MULTI_SESSION
-               priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK, NULL);
-#else
-               priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
-#endif
-       }
-
-       alc5658_givesem(&priv->pendsem);
-
-       /* Return any pending buffers in our done queue */
-
-       alc5658_returnbuffers(priv);
-
-       /* Close the message queue */
-
-       mq_close(priv->mq);
-       mq_unlink(priv->mqname);
-       priv->mq = NULL;
-
-       /* Send an AUDIO_MSG_COMPLETE message to the client */
-
-#ifdef CONFIG_AUDIO_MULTI_SESSION
-       priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_COMPLETE, NULL, OK, NULL);
-#else
-       priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_COMPLETE, NULL, OK);
-#endif
-
-       audvdbg("Exit\n");
-       return NULL;
-}
-
-/****************************************************************************
  * Name: alc5658_audio_output
  *
  * Description:
@@ -1427,10 +1058,9 @@ static void *alc5658_workerthread(pthread_addr_t pvarg)
  *   None.  No failures are detected.
  *
  ****************************************************************************/
-
 static void alc5658_audio_output(FAR struct alc5658_dev_s *priv)
 {
-       alc5658_exec_i2c_script(priv, codec_init_script, sizeof(codec_init_script) / sizeof(t_codec_init_script_entry));
+       alc5658_exec_i2c_script(priv, codec_init_out_script, sizeof(codec_init_out_script) / sizeof(t_codec_init_script_entry));
 }
 
 /****************************************************************************
@@ -1446,9 +1076,9 @@ static void alc5658_audio_output(FAR struct alc5658_dev_s *priv)
  *   None.  No failures are detected.
  *
  ****************************************************************************/
-
 static void alc5658_audio_input(FAR struct alc5658_dev_s *priv)
 {
+       alc5658_exec_i2c_script(priv, codec_init_in_script, sizeof(codec_init_in_script) / sizeof(t_codec_init_script_entry));
 }
 
 /****************************************************************************
@@ -1464,10 +1094,10 @@ static void alc5658_audio_input(FAR struct alc5658_dev_s *priv)
  *   None
  *
  ****************************************************************************/
-
 #ifdef ALC5658_USE_FFLOCK_INT
 static void alc5658_configure_ints(FAR struct alc5658_dev_s *priv)
 {
+       /* Missing */
 }
 #endif
 
@@ -1484,7 +1114,6 @@ static void alc5658_configure_ints(FAR struct alc5658_dev_s *priv)
  *   None
  *
  ****************************************************************************/
-
 static void alc5658_hw_reset(FAR struct alc5658_dev_s *priv)
 {
 
@@ -1509,7 +1138,7 @@ static void alc5658_hw_reset(FAR struct alc5658_dev_s *priv)
 
        /* Configure the FLL and the LRCLK */
 
-       alc5658_setbitrate(priv);
+       alc5658_set_i2s_samplerate(priv);
 
        /* Dump some information and return the device instance */
 
@@ -1537,7 +1166,6 @@ static void alc5658_hw_reset(FAR struct alc5658_dev_s *priv)
  *   success; NULL is returned on failure.
  *
  ****************************************************************************/
-
 FAR struct audio_lowerhalf_s *alc5658_initialize(FAR struct i2c_dev_s *i2c, FAR struct i2s_dev_s *i2s, FAR struct alc5658_lower_s *lower)
 {
 
@@ -1558,7 +1186,7 @@ FAR struct audio_lowerhalf_s *alc5658_initialize(FAR struct i2c_dev_s *i2c, FAR
                priv->i2c = i2c;
                priv->i2s = i2s;
 
-               sem_init(&priv->pendsem, 0, 1);
+               sem_init(&priv->devsem, 0, 1);
                dq_init(&priv->pendq);
                dq_init(&priv->doneq);
 
@@ -1586,7 +1214,7 @@ FAR struct audio_lowerhalf_s *alc5658_initialize(FAR struct i2c_dev_s *i2c, FAR
        return NULL;
 
 errout_with_dev:
-       sem_destroy(&priv->pendsem);
+       sem_destroy(&priv->devsem);
        kmm_free(priv);
        return NULL;
 }
index 826e914..16c6530 100644 (file)
@@ -33,7 +33,7 @@
  * Pre-processor Definitions
  ****************************************************************************/
        
-#define ALC5658_DEFAULT_SAMPRATE       48000
+#define ALC5658_DEFAULT_SAMPRATE       16000
 #define ALC5658_DEFAULT_NCHANNELS      2
 #define ALC5658_DEFAULT_BPSAMP         16
 #define FAIL                           0xFFFF
@@ -51,6 +51,8 @@
 /****************************************************************************
  * Public Types
  ****************************************************************************/
+/* This should be put under hammer to strip size 
+by for status variables */
 
 struct alc5658_dev_s {
        /* We are an audio lower half driver (We are also the upper "half" of
@@ -71,11 +73,8 @@ struct alc5658_dev_s {
        FAR struct i2s_dev_s *i2s;      /* I2S driver to use */
        struct dq_queue_s pendq;        /* Queue of pending buffers to be sent */
        struct dq_queue_s doneq;        /* Queue of sent buffers to be returned */
-       mqd_t mq;                                       /* Message queue for receiving messages */
-       char mqname[16];                        /* Our message queue name */
-       pthread_t threadid;                     /* ID of our thread */
-       uint32_t bitrate;                       /* Actual programmed bit rate */
-       sem_t pendsem;                          /* Protect pendq */
+       sem_t devsem;                           /* Protection for both pendq & dev*/
+
 #ifdef ALC5658_USE_FFLOCK_INT
        struct work_s work;                     /* Interrupt work */
 #endif
@@ -100,6 +99,7 @@ struct alc5658_dev_s {
 #endif
        bool reserved;                          /* True: Device is reserved */
        volatile int result;            /* The result of the last transfer */
+       bool inout;                                     /* True: IN device */
 };
 
 /****************************************************************************
@@ -129,8 +129,8 @@ static void alc5658_setbass(FAR struct alc5658_dev_s *priv, uint8_t bass);
 static void alc5658_settreble(FAR struct alc5658_dev_s *priv, uint8_t treble);
 #endif
 
-static void alc5658_setdatawidth(FAR struct alc5658_dev_s *priv);
-static void alc5658_setbitrate(FAR struct alc5658_dev_s *priv);
+static void alc5658_set_i2s_datawidth(FAR struct alc5658_dev_s *priv);
+static void alc5658_set_i2s_samplerate(FAR struct alc5658_dev_s *priv);
 
 /* Audio lower half methods (and close friends) */
 
@@ -141,9 +141,6 @@ static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR void *sessio
 static int alc5658_configure(FAR struct audio_lowerhalf_s *dev, FAR const struct audio_caps_s *caps);
 #endif
 static int alc5658_shutdown(FAR struct audio_lowerhalf_s *dev);
-static void alc5658_senddone(FAR struct i2s_dev_s *i2s, FAR struct ap_buffer_s *apb, FAR void *arg, int result);
-static void alc5658_returnbuffers(FAR struct alc5658_dev_s *priv);
-static int alc5658_sendbuffer(FAR struct alc5658_dev_s *priv);
 
 #ifdef CONFIG_AUDIO_MULTI_SESSION
 static int alc5658_start(FAR struct audio_lowerhalf_s *dev, FAR void *session);
@@ -187,10 +184,8 @@ static void alc5658_interrupt_work(FAR void *arg);
 static int alc5658_interrupt(FAR const struct alc5658_lower_s *lower, FAR void *arg);
 #endif
 
-static void *alc5658_workerthread(pthread_addr_t pvarg);
 
 /* Initialization */
-
 static void alc5658_audio_output(FAR struct alc5658_dev_s *priv);
 static void alc5658_audio_input(FAR struct alc5658_dev_s *priv);
 #ifdef ALC5658_USE_FFLOCK_INT
@@ -199,11 +194,8 @@ static void alc5658_configure_ints(FAR struct alc5658_dev_s *priv);
 #define       alc5658_configure_ints(p)
 #endif
 static void alc5658_hw_reset(FAR struct alc5658_dev_s *priv);
+uint16_t alc5658_readreg(FAR struct alc5658_dev_s *priv, uint16_t regaddr);
 
-#if defined(CONFIG_ALC5658_REGDUMP) || defined(CONFIG_ALC5658_CLKDEBUG)
-struct alc5658_dev_s;
-uint16_t alc5658_readreg(FAR struct alc5658_dev_s *priv, uint8_t regaddr);
-#endif
 
 #endif                                                 /* CONFIG_AUDIO */
 #endif                                                 /* __DRIVERS_AUDIO_ALC5658_H */
index 96e615f..810b67f 100644 (file)
@@ -91,7 +91,7 @@
  *
  ****************************************************************************/
 
-#define I2S_RXSAMPLERATE(d,f) ((d)->ops->i2s_rxsamplerate(d,r))
+#define I2S_RXSAMPLERATE(d,f) ((d)->ops->i2s_rxsamplerate(d,f))
 
 /****************************************************************************
  * Name: I2S_RXDATAWIDTH
  *
  ****************************************************************************/
 
-#define I2S_TXSAMPLERATE(d,f) ((d)->ops->i2s_txsamplerate(d,r))
+#define I2S_TXSAMPLERATE(d,f) ((d)->ops->i2s_txsamplerate(d,f))
 
 /****************************************************************************
  * Name: I2S_TXDATAWIDTH