You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/01/25 02:46:40 UTC
(nuttx) branch master updated: samv7: refactor DAC driver
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new fba4b2593c samv7: refactor DAC driver
fba4b2593c is described below
commit fba4b2593c3ba8e25464e146f3e65e646c94dda3
Author: Michal Lenc <mi...@seznam.cz>
AuthorDate: Wed Jan 24 14:09:09 2024 +0100
samv7: refactor DAC driver
This commit refactors DAC driver. The functionality remains the same
but driver start up is now done in dac_setup (after application called
open function) instead of sam_dac_initialize (called from BSP). This
ensures that driver does not take resources (timer, interrupt) until
opened. Implementation of dac_shutdown is also provided, therefore
the driver frees resources once closed.
This change is consistent with other drivers implementation.
Signed-off-by: Michal Lenc <mi...@seznam.cz>
---
arch/arm/src/samv7/sam_dac.c | 153 ++++++++++++++++++++++++++++++++-----------
1 file changed, 114 insertions(+), 39 deletions(-)
diff --git a/arch/arm/src/samv7/sam_dac.c b/arch/arm/src/samv7/sam_dac.c
index 1601e27c22..1fb2d3330a 100644
--- a/arch/arm/src/samv7/sam_dac.c
+++ b/arch/arm/src/samv7/sam_dac.c
@@ -68,7 +68,7 @@
struct sam_dac_s
{
- uint8_t initialized : 1; /* True, the DAC block has been initialized */
+ uint8_t users; /* Number of channels using peripheral */
#ifdef CONFIG_SAMV7_DAC_TRIGGER
TC_HANDLE tc; /* Timer handle */
#endif
@@ -78,7 +78,7 @@ struct sam_dac_s
struct sam_chan_s
{
- uint8_t inuse : 1; /* True, the driver is in use and not available */
+ bool inuse; /* True, the driver is in use and not available */
uint8_t intf; /* DAC zero-based interface number (0 or 1) */
uint32_t dro; /* Conversion Data Register */
#ifdef CONFIG_SAMV7_DAC_TRIGGER
@@ -134,7 +134,7 @@ static struct sam_chan_s g_dac1priv =
.intf = 0,
.dro = SAM_DACC_CDR0,
#ifdef CONFIG_SAMV7_DAC_TRIGGER
- .reg_dacc_trigr_clear = DACC_TRIGR_TRGSEL0_MASK,
+ .reg_dacc_trigr_clear = DACC_TRIGR_TRGSEL0_MASK | DACC_TRIGR_TRGEN0_EN,
.reg_dacc_trigr_set = DACC_TRIGR_TRGSEL0(
CONFIG_SAMV7_DAC_TRIGGER_SELECT) |
DACC_TRIGR_TRGEN0,
@@ -154,7 +154,7 @@ static struct sam_chan_s g_dac2priv =
.intf = 1,
.dro = SAM_DACC_CDR1,
#ifdef CONFIG_SAMV7_DAC_TRIGGER
- .reg_dacc_trigr_clear = DACC_TRIGR_TRGSEL1_MASK,
+ .reg_dacc_trigr_clear = DACC_TRIGR_TRGSEL1_MASK | DACC_TRIGR_TRGEN1_EN,
.reg_dacc_trigr_set = DACC_TRIGR_TRGSEL1(
CONFIG_SAMV7_DAC_TRIGGER_SELECT) |
DACC_TRIGR_TRGEN1,
@@ -226,15 +226,46 @@ static int dac_interrupt(int irq, void *context, void *arg)
static void dac_reset(struct dac_dev_s *dev)
{
+ struct sam_chan_s *chan = dev->ad_priv;
+#ifdef CONFIG_SAMV7_DAC_TRIGGER
+ uint32_t regval;
+#endif
irqstate_t flags;
/* Reset only the selected DAC channel; the other DAC channel must remain
- * functional.
+ * functional. The controller however does not have an option to reset
+ * single channel, therefore we have to do this manually by writing zeroes
+ * to all important registers.
+ */
+
+ /* This should be called only before dac_setup(), therefore the channel
+ * should not be in use. Skip reset if it is.
*/
- flags = enter_critical_section();
+ if (chan->inuse)
+ {
+ /* Yes.. then return EBUSY */
+
+ return;
+ }
+
+ flags = enter_critical_section();
+
+ /* Disable channel */
+
+ putreg32(1u << chan->intf, SAM_DACC_CHDR);
+
+ /* Disable interrupts */
-#warning "Missing logic"
+ dac_txint(dev, false);
+
+#ifdef CONFIG_SAMV7_DAC_TRIGGER
+ /* Reset trigger mode */
+
+ regval = getreg32(SAM_DACC_TRIGR);
+ regval &= ~chan->reg_dacc_trigr_clear;
+ putreg32(regval, SAM_DACC_TRIGR);
+#endif
leave_critical_section(flags);
}
@@ -257,7 +288,40 @@ static void dac_reset(struct dac_dev_s *dev)
static int dac_setup(struct dac_dev_s *dev)
{
-#warning "Missing logic"
+ struct sam_chan_s *chan = dev->ad_priv;
+ int ret;
+
+ /* Initialize the DAC peripheral module */
+
+ ret = dac_module_init();
+ if (ret < 0)
+ {
+ aerr("ERROR: Failed to initialize the DAC peripheral module: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Add channel user. We can do this because the upper layer checks
+ * whether the device is opened for the first time and calls dac_setup
+ * only if this is true. Therefore there can not be a situation where
+ * the application would open DAC1 two times and dac_setup would be called
+ * two times. We however have to check number of users (DAC0 and DAC1)
+ * to know whether we want to disable the entire peripheral during
+ * shutdown.
+ */
+
+ g_dacmodule.users++;
+
+ /* Configure the selected DAC channel */
+
+ ret = dac_channel_init(chan);
+ if (ret < 0)
+ {
+ aerr("ERROR: Failed to initialize DAC channel %d: %d\n",
+ chan->intf, ret);
+ return ret;
+ }
+
return OK;
}
@@ -277,7 +341,43 @@ static int dac_setup(struct dac_dev_s *dev)
static void dac_shutdown(struct dac_dev_s *dev)
{
-#warning "Missing logic"
+ struct sam_chan_s *chan = dev->ad_priv;
+
+ /* We can use dac_reset() to disable the channel. */
+
+ chan->inuse = false;
+ dac_reset(dev);
+
+ /* Decrement number of peripheral users. */
+
+ g_dacmodule.users--;
+
+ if (g_dacmodule.users == 0)
+ {
+ /* This means there are no more channels using the peripheral. We
+ * can disable entire peripheral and free timer.
+ */
+
+ /* Reset peripheral. This will simulate HW reset and clean all
+ * registers.
+ */
+
+ putreg32(DACC_CR_SWRST, SAM_DACC_CR);
+
+ /* Disable interrupt */
+
+ up_disable_irq(SAM_IRQ_DACC);
+
+ /* Detach interrupt */
+
+ irq_detach(SAM_IRQ_DACC);
+
+#ifdef CONFIG_SAMV7_DAC_TRIGGER
+ /* Free timer */
+
+ dac_timer_free(&g_dacmodule);
+#endif
+ }
}
/****************************************************************************
@@ -327,7 +427,7 @@ static int dac_send(struct dac_dev_s *dev, struct dac_msg_s *msg)
/* Interrupt based transfer */
- putreg16(msg->am_data >> 16, chan->dro);
+ putreg32(msg->am_data & DACC_CDR_DATA0_MASK, chan->dro);
return OK;
}
@@ -483,11 +583,11 @@ static int dac_channel_init(struct sam_chan_s *chan)
/* Enable DAC Channel */
- putreg32(1 << chan->intf, SAM_DACC_CHER);
+ putreg32(1u << chan->intf, SAM_DACC_CHER);
/* Mark the DAC channel "in-use" */
- chan->inuse = 1;
+ chan->inuse = true;
return OK;
}
@@ -509,9 +609,9 @@ static int dac_module_init(void)
uint32_t regval;
int ret;
- /* Has the DAC block already been initialized? */
+ /* Has the DAC block already been users? */
- if (g_dacmodule.initialized)
+ if (g_dacmodule.users > 0)
{
/* Yes.. then return success We only have to do this once */
@@ -571,9 +671,6 @@ static int dac_module_init(void)
ainfo("Enable the DAC interrupt: irq=%d\n", SAM_IRQ_DACC);
up_enable_irq(SAM_IRQ_DACC);
- /* Mark the DAC module as initialized */
-
- g_dacmodule.initialized = 1;
return OK;
}
@@ -598,8 +695,6 @@ static int dac_module_init(void)
struct dac_dev_s *sam_dac_initialize(int intf)
{
struct dac_dev_s *dev;
- struct sam_chan_s *chan;
- int ret;
#ifdef CONFIG_SAMV7_DAC0
if (intf == 0)
@@ -622,26 +717,6 @@ struct dac_dev_s *sam_dac_initialize(int intf)
return NULL;
}
- /* Initialize the DAC peripheral module */
-
- ret = dac_module_init();
- if (ret < 0)
- {
- aerr("ERROR: Failed to initialize the DAC peripheral module: %d\n",
- ret);
- return NULL;
- }
-
- /* Configure the selected DAC channel */
-
- chan = dev->ad_priv;
- ret = dac_channel_init(chan);
- if (ret < 0)
- {
- aerr("ERROR: Failed to initialize DAC channel %d: %d\n", intf, ret);
- return NULL;
- }
-
return dev;
}