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 <michallenc@seznam.cz>
This commit is contained in:
parent
5018964155
commit
fba4b2593c
@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
struct sam_dac_s
|
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
|
#ifdef CONFIG_SAMV7_DAC_TRIGGER
|
||||||
TC_HANDLE tc; /* Timer handle */
|
TC_HANDLE tc; /* Timer handle */
|
||||||
#endif
|
#endif
|
||||||
@ -78,7 +78,7 @@ struct sam_dac_s
|
|||||||
|
|
||||||
struct sam_chan_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) */
|
uint8_t intf; /* DAC zero-based interface number (0 or 1) */
|
||||||
uint32_t dro; /* Conversion Data Register */
|
uint32_t dro; /* Conversion Data Register */
|
||||||
#ifdef CONFIG_SAMV7_DAC_TRIGGER
|
#ifdef CONFIG_SAMV7_DAC_TRIGGER
|
||||||
@ -134,7 +134,7 @@ static struct sam_chan_s g_dac1priv =
|
|||||||
.intf = 0,
|
.intf = 0,
|
||||||
.dro = SAM_DACC_CDR0,
|
.dro = SAM_DACC_CDR0,
|
||||||
#ifdef CONFIG_SAMV7_DAC_TRIGGER
|
#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(
|
.reg_dacc_trigr_set = DACC_TRIGR_TRGSEL0(
|
||||||
CONFIG_SAMV7_DAC_TRIGGER_SELECT) |
|
CONFIG_SAMV7_DAC_TRIGGER_SELECT) |
|
||||||
DACC_TRIGR_TRGEN0,
|
DACC_TRIGR_TRGEN0,
|
||||||
@ -154,7 +154,7 @@ static struct sam_chan_s g_dac2priv =
|
|||||||
.intf = 1,
|
.intf = 1,
|
||||||
.dro = SAM_DACC_CDR1,
|
.dro = SAM_DACC_CDR1,
|
||||||
#ifdef CONFIG_SAMV7_DAC_TRIGGER
|
#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(
|
.reg_dacc_trigr_set = DACC_TRIGR_TRGSEL1(
|
||||||
CONFIG_SAMV7_DAC_TRIGGER_SELECT) |
|
CONFIG_SAMV7_DAC_TRIGGER_SELECT) |
|
||||||
DACC_TRIGR_TRGEN1,
|
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)
|
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;
|
irqstate_t flags;
|
||||||
|
|
||||||
/* Reset only the selected DAC channel; the other DAC channel must remain
|
/* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
flags = enter_critical_section();
|
/* This should be called only before dac_setup(), therefore the channel
|
||||||
|
* should not be in use. Skip reset if it is.
|
||||||
|
*/
|
||||||
|
|
||||||
#warning "Missing logic"
|
if (chan->inuse)
|
||||||
|
{
|
||||||
|
/* Yes.. then return EBUSY */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
/* Disable channel */
|
||||||
|
|
||||||
|
putreg32(1u << chan->intf, SAM_DACC_CHDR);
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
|
||||||
|
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);
|
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)
|
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;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +341,43 @@ static int dac_setup(struct dac_dev_s *dev)
|
|||||||
|
|
||||||
static void dac_shutdown(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 */
|
/* Interrupt based transfer */
|
||||||
|
|
||||||
putreg16(msg->am_data >> 16, chan->dro);
|
putreg32(msg->am_data & DACC_CDR_DATA0_MASK, chan->dro);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -483,11 +583,11 @@ static int dac_channel_init(struct sam_chan_s *chan)
|
|||||||
|
|
||||||
/* Enable DAC Channel */
|
/* Enable DAC Channel */
|
||||||
|
|
||||||
putreg32(1 << chan->intf, SAM_DACC_CHER);
|
putreg32(1u << chan->intf, SAM_DACC_CHER);
|
||||||
|
|
||||||
/* Mark the DAC channel "in-use" */
|
/* Mark the DAC channel "in-use" */
|
||||||
|
|
||||||
chan->inuse = 1;
|
chan->inuse = true;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,9 +609,9 @@ static int dac_module_init(void)
|
|||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
int ret;
|
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 */
|
/* 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);
|
ainfo("Enable the DAC interrupt: irq=%d\n", SAM_IRQ_DACC);
|
||||||
up_enable_irq(SAM_IRQ_DACC);
|
up_enable_irq(SAM_IRQ_DACC);
|
||||||
|
|
||||||
/* Mark the DAC module as initialized */
|
|
||||||
|
|
||||||
g_dacmodule.initialized = 1;
|
|
||||||
return OK;
|
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 *sam_dac_initialize(int intf)
|
||||||
{
|
{
|
||||||
struct dac_dev_s *dev;
|
struct dac_dev_s *dev;
|
||||||
struct sam_chan_s *chan;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SAMV7_DAC0
|
#ifdef CONFIG_SAMV7_DAC0
|
||||||
if (intf == 0)
|
if (intf == 0)
|
||||||
@ -622,26 +717,6 @@ struct dac_dev_s *sam_dac_initialize(int intf)
|
|||||||
return NULL;
|
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;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user