samv7:twihs driver add reference counting
This commit is contained in:
parent
d8da813562
commit
d9d32ac808
@ -151,7 +151,7 @@ struct twi_dev_s
|
|||||||
struct i2c_msg_s *msg; /* Message list */
|
struct i2c_msg_s *msg; /* Message list */
|
||||||
uint32_t twiclk; /* TWIHS input clock frequency */
|
uint32_t twiclk; /* TWIHS input clock frequency */
|
||||||
uint32_t frequency; /* TWIHS transfer clock frequency */
|
uint32_t frequency; /* TWIHS transfer clock frequency */
|
||||||
bool initd; /* True :device has been initialized */
|
int refs; /* Reference count */
|
||||||
uint8_t msgc; /* Number of message in the message list */
|
uint8_t msgc; /* Number of message in the message list */
|
||||||
|
|
||||||
sem_t exclsem; /* Only one thread can access at a time */
|
sem_t exclsem; /* Only one thread can access at a time */
|
||||||
@ -1118,6 +1118,10 @@ static int twi_reset(FAR struct i2c_master_s *dev)
|
|||||||
|
|
||||||
DEBUGASSERT(priv != NULL);
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
|
/* Our caller must own a ref */
|
||||||
|
|
||||||
|
DEBUGASSERT(priv->refs > 0);
|
||||||
|
|
||||||
/* Get exclusive access to the TWIHS device */
|
/* Get exclusive access to the TWIHS device */
|
||||||
|
|
||||||
twi_takesem(&priv->exclsem);
|
twi_takesem(&priv->exclsem);
|
||||||
@ -1342,6 +1346,7 @@ struct i2c_master_s *sam_i2cbus_initialize(int bus)
|
|||||||
{
|
{
|
||||||
struct twi_dev_s *priv;
|
struct twi_dev_s *priv;
|
||||||
uint32_t frequency;
|
uint32_t frequency;
|
||||||
|
const struct twi_attr_s *attr = 0;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -1352,8 +1357,8 @@ struct i2c_master_s *sam_i2cbus_initialize(int bus)
|
|||||||
{
|
{
|
||||||
/* Select up TWIHS0 and setup invariant attributes */
|
/* Select up TWIHS0 and setup invariant attributes */
|
||||||
|
|
||||||
priv = &g_twi0;
|
priv = &g_twi0;
|
||||||
priv->attr = &g_twi0attr;
|
attr = &g_twi0attr;
|
||||||
|
|
||||||
/* Select the (initial) TWIHS frequency */
|
/* Select the (initial) TWIHS frequency */
|
||||||
|
|
||||||
@ -1366,8 +1371,8 @@ struct i2c_master_s *sam_i2cbus_initialize(int bus)
|
|||||||
{
|
{
|
||||||
/* Select up TWIHS1 and setup invariant attributes */
|
/* Select up TWIHS1 and setup invariant attributes */
|
||||||
|
|
||||||
priv = &g_twi1;
|
priv = &g_twi1;
|
||||||
priv->attr = &g_twi1attr;
|
attr = &g_twi1attr;
|
||||||
|
|
||||||
/* Select the (initial) TWIHS frequency */
|
/* Select the (initial) TWIHS frequency */
|
||||||
|
|
||||||
@ -1380,8 +1385,8 @@ struct i2c_master_s *sam_i2cbus_initialize(int bus)
|
|||||||
{
|
{
|
||||||
/* Select up TWIHS2 and setup invariant attributes */
|
/* Select up TWIHS2 and setup invariant attributes */
|
||||||
|
|
||||||
priv = &g_twi2;
|
priv = &g_twi2;
|
||||||
priv->attr = &g_twi2attr;
|
attr = &g_twi2attr;
|
||||||
|
|
||||||
/* Select the (initial) TWIHS frequency */
|
/* Select the (initial) TWIHS frequency */
|
||||||
|
|
||||||
@ -1394,14 +1399,16 @@ struct i2c_master_s *sam_i2cbus_initialize(int bus)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform one-time TWIHS initialization */
|
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
/* Has the device already been initialized? */
|
/* Has the device already been initialized? */
|
||||||
|
|
||||||
if (!priv->initd)
|
if ((volatile int)priv->refs++ == 0)
|
||||||
{
|
{
|
||||||
|
/* Perform one-time TWIHS initialization */
|
||||||
|
|
||||||
|
priv->attr = attr;
|
||||||
|
|
||||||
/* Allocate a watchdog timer */
|
/* Allocate a watchdog timer */
|
||||||
|
|
||||||
priv->timeout = wd_create();
|
priv->timeout = wd_create();
|
||||||
@ -1438,10 +1445,6 @@ struct i2c_master_s *sam_i2cbus_initialize(int bus)
|
|||||||
/* Perform repeatable TWIHS hardware initialization */
|
/* Perform repeatable TWIHS hardware initialization */
|
||||||
|
|
||||||
twi_hw_initialize(priv, frequency);
|
twi_hw_initialize(priv, frequency);
|
||||||
|
|
||||||
/* Now it has been initialized */
|
|
||||||
|
|
||||||
priv->initd = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
@ -1452,6 +1455,7 @@ errout_with_wdog:
|
|||||||
priv->timeout = NULL;
|
priv->timeout = NULL;
|
||||||
|
|
||||||
errout_with_irq:
|
errout_with_irq:
|
||||||
|
priv->refs--;
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1469,28 +1473,40 @@ int sam_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
|
|||||||
struct twi_dev_s *priv = (struct twi_dev_s *) dev;
|
struct twi_dev_s *priv = (struct twi_dev_s *) dev;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
|
|
||||||
i2cinfo("TWIHS%d Un-initializing\n", priv->attr->twi);
|
DEBUGASSERT(priv);
|
||||||
|
|
||||||
|
/* Decrement reference count and check for underflow */
|
||||||
|
|
||||||
|
if (priv->refs == 0)
|
||||||
|
{
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2cinfo("TWIHS%d Un-initializing refs:%d\n", priv->attr->twi, priv->refs);
|
||||||
|
|
||||||
/* Disable TWIHS interrupts */
|
/* Disable TWIHS interrupts */
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
up_disable_irq(priv->attr->irq);
|
|
||||||
|
|
||||||
/* Reset data structures */
|
if (--priv->refs == 0)
|
||||||
|
{
|
||||||
|
up_disable_irq(priv->attr->irq);
|
||||||
|
|
||||||
sem_destroy(&priv->exclsem);
|
/* Reset data structures */
|
||||||
sem_destroy(&priv->waitsem);
|
|
||||||
|
|
||||||
/* Free the watchdog timer */
|
sem_destroy(&priv->exclsem);
|
||||||
|
sem_destroy(&priv->waitsem);
|
||||||
|
|
||||||
wd_delete(priv->timeout);
|
/* Free the watchdog timer */
|
||||||
priv->timeout = NULL;
|
|
||||||
|
|
||||||
/* Detach Interrupt Handler */
|
wd_delete(priv->timeout);
|
||||||
|
priv->timeout = NULL;
|
||||||
|
|
||||||
(void)irq_detach(priv->attr->irq);
|
/* Detach Interrupt Handler */
|
||||||
|
|
||||||
|
(void)irq_detach(priv->attr->irq);
|
||||||
|
}
|
||||||
|
|
||||||
priv->initd = false;
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user