zephyr/drivers/counter/counter_qmsi_aonpt.c
Leandro Pereira 732424f065 drivers, net: Clean up semaphore initialization
Change the common "init with 0" + "give" idiom to "init with 1".  This
won't change the behavior or performance, but should decrease the size
ever so slightly.

This change has been performed mechanically with the following
Coccinelle script:

    @@
    expression SEM;
    expression LIMIT;
    expression TIMEOUT;
    @@

    - k_sem_init(SEM, 0, LIMIT);
    - k_sem_give(SEM);
    + k_sem_init(SEM, 1, LIMIT);

Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
2017-07-27 15:23:07 -04:00

251 lines
5.3 KiB
C

/*
* Copyright (c) 2016 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <device.h>
#include <init.h>
#include <drivers/ioapic.h>
#include <counter.h>
#include <power.h>
#include <soc.h>
#include <misc/util.h>
#include "qm_aon_counters.h"
#include "qm_isr.h"
static void aonpt_int_callback(void *user_data);
static counter_callback_t user_cb;
struct aon_data {
#ifdef CONFIG_AON_API_REENTRANCY
struct k_sem sem;
#endif
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
u32_t device_power_state;
#endif
};
#define AONPT_HAS_CONTEXT_DATA \
(CONFIG_AON_API_REENTRANCY || CONFIG_DEVICE_POWER_MANAGEMENT)
#if AONPT_HAS_CONTEXT_DATA
static struct aon_data aonpt_context;
#define AONPT_CONTEXT (&aonpt_context)
#else
#define AONPT_CONTEXT (NULL)
#endif
#ifdef CONFIG_AON_API_REENTRANCY
#define RP_GET(dev) (&((struct aon_data *)(dev->driver_data))->sem)
#else
#define RP_GET(dev) (NULL)
#endif
static int aon_timer_qmsi_start(struct device *dev)
{
qm_aonpt_config_t qmsi_cfg;
int result = 0;
user_cb = NULL;
qmsi_cfg.callback = NULL;
qmsi_cfg.int_en = false;
/* AONPT is a countdown timer. So, set the initial value to
* the maximum value.
*/
qmsi_cfg.count = 0xffffffff;
qmsi_cfg.callback_data = NULL;
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_take(RP_GET(dev), K_FOREVER);
}
if (qm_aonpt_set_config(QM_AONC_0, &qmsi_cfg)) {
result = -EIO;
}
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_give(RP_GET(dev));
}
return result;
}
static int aon_timer_qmsi_stop(struct device *dev)
{
qm_aonpt_config_t qmsi_cfg;
qmsi_cfg.callback = NULL;
qmsi_cfg.int_en = false;
qmsi_cfg.count = 0;
qmsi_cfg.callback_data = NULL;
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_take(RP_GET(dev), K_FOREVER);
}
qm_aonpt_set_config(QM_AONC_0, &qmsi_cfg);
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_give(RP_GET(dev));
}
return 0;
}
static u32_t aon_timer_qmsi_read(struct device *dev)
{
u32_t value;
qm_aonpt_get_value(QM_AONC_0, &value);
return value;
}
static int aon_timer_qmsi_set_alarm(struct device *dev,
counter_callback_t callback,
u32_t count, void *user_data)
{
qm_aonpt_config_t qmsi_cfg;
int result = 0;
/* Check if timer has been started */
if (QM_AONC[QM_AONC_0]->aonpt_cfg == 0) {
return -ENOTSUP;
}
user_cb = callback;
qmsi_cfg.callback = aonpt_int_callback;
qmsi_cfg.int_en = true;
qmsi_cfg.count = count;
qmsi_cfg.callback_data = user_data;
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_take(RP_GET(dev), K_FOREVER);
}
if (qm_aonpt_set_config(QM_AONC_0, &qmsi_cfg)) {
user_cb = NULL;
result = -EIO;
}
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_give(RP_GET(dev));
}
return result;
}
static u32_t aon_timer_qmsi_get_pending_int(struct device *dev)
{
return QM_AONC[QM_AONC_0]->aonpt_stat;
}
static const struct counter_driver_api aon_timer_qmsi_api = {
.start = aon_timer_qmsi_start,
.stop = aon_timer_qmsi_stop,
.read = aon_timer_qmsi_read,
.set_alarm = aon_timer_qmsi_set_alarm,
.get_pending_int = aon_timer_qmsi_get_pending_int,
};
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
static qm_aonc_context_t aonc_ctx;
static void aonpt_qmsi_set_power_state(struct device *dev, u32_t power_state)
{
struct aon_data *context = dev->driver_data;
context->device_power_state = power_state;
}
static u32_t aonpt_qmsi_get_power_state(struct device *dev)
{
struct aon_data *context = dev->driver_data;
return context->device_power_state;
}
static int aonpt_suspend_device(struct device *dev)
{
qm_aonpt_save_context(QM_AONC_0, &aonc_ctx);
aonpt_qmsi_set_power_state(dev, DEVICE_PM_SUSPEND_STATE);
return 0;
}
static int aonpt_resume_device_from_suspend(struct device *dev)
{
qm_aonpt_restore_context(QM_AONC_0, &aonc_ctx);
aonpt_qmsi_set_power_state(dev, DEVICE_PM_ACTIVE_STATE);
return 0;
}
/*
* Implements the driver control management functionality
* the *context may include IN data or/and OUT data
*/
static int aonpt_qmsi_device_ctrl(struct device *dev, u32_t ctrl_command,
void *context)
{
if (ctrl_command == DEVICE_PM_SET_POWER_STATE) {
if (*((u32_t *)context) == DEVICE_PM_SUSPEND_STATE) {
return aonpt_suspend_device(dev);
} else if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) {
return aonpt_resume_device_from_suspend(dev);
}
} else if (ctrl_command == DEVICE_PM_GET_POWER_STATE) {
*((u32_t *)context) = aonpt_qmsi_get_power_state(dev);
return 0;
}
return 0;
}
#else
#define aonpt_qmsi_set_power_state(...)
#endif
static int aon_timer_init(struct device *dev)
{
dev->driver_api = &aon_timer_qmsi_api;
user_cb = NULL;
IRQ_CONNECT(IRQ_GET_NUMBER(QM_IRQ_AONPT_0_INT),
CONFIG_AON_TIMER_IRQ_PRI, qm_aonpt_0_isr, NULL,
IOAPIC_EDGE | IOAPIC_HIGH);
irq_enable(IRQ_GET_NUMBER(QM_IRQ_AONPT_0_INT));
QM_IR_UNMASK_INTERRUPTS(QM_INTERRUPT_ROUTER->aonpt_0_int_mask);
if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_init(RP_GET(dev), 1, UINT_MAX);
}
aonpt_qmsi_set_power_state(dev, DEVICE_PM_ACTIVE_STATE);
return 0;
}
DEVICE_DEFINE(aon_timer, CONFIG_AON_TIMER_QMSI_DEV_NAME, aon_timer_init,
aonpt_qmsi_device_ctrl, AONPT_CONTEXT, NULL, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&aon_timer_qmsi_api);
static void aonpt_int_callback(void *user_data)
{
if (user_cb) {
(*user_cb)(DEVICE_GET(aon_timer), user_data);
}
}