aio: introduce DesignWare AIO/Comparator driver

This adds the driver to support DesignWare AIO/Comparator
under drivers/aio.

Change-Id: Id6cb1b507c0526098f163f74c188e990590797c2
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Signed-off-by: Daniel Leung <daniel.leung@intel.com>
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Daniel Leung 2015-11-21 21:33:43 -05:00 committed by Anas Nashif
commit a789cc0c02
8 changed files with 464 additions and 0 deletions

View file

@ -61,4 +61,6 @@ source "drivers/clock_control/Kconfig"
source "drivers/ipi/Kconfig" source "drivers/ipi/Kconfig"
source "drivers/aio/Kconfig"
endmenu endmenu

View file

@ -22,3 +22,4 @@ obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_RTC) += rtc/ obj-$(CONFIG_RTC) += rtc/
obj-$(CONFIG_CLOCK_CONTROL) += clock_control/ obj-$(CONFIG_CLOCK_CONTROL) += clock_control/
obj-$(CONFIG_IPI) += ipi/ obj-$(CONFIG_IPI) += ipi/
obj-y += aio/

39
drivers/aio/Kconfig Normal file
View file

@ -0,0 +1,39 @@
# Kconfig - AIO/Comparator configuration options
#
#
# Copyright (c) 2015 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# AIO/Comparator options
#
menuconfig AIO_COMPARATOR
bool
prompt "AIO/Comparator Configuration"
default n
config AIO_DW_COMPARATOR
bool "Enable DesignWare AIO/comparator driver"
default n
depends on AIO_COMPARATOR
help
DesignWare AIO/Comparator driver.
config AIO_DW_COMPARATOR_BASE_ADDR
hex "Base address for DesignWare AIO/comparator"
depends on AIO_DW_COMPARATOR
help
Base address for memory mapped registers.

5
drivers/aio/Makefile Normal file
View file

@ -0,0 +1,5 @@
ccflags-y +=-I$(srctree)/arch/$(ARCH)
ccflags-y +=-I$(srctree)/arch/$(ARCH)/platforms/$(subst $(DQUOTE),,$(CONFIG_PLATFORM))
asflags-y +=-I$(srctree)/arch/$(ARCH)/platforms/$(subst $(DQUOTE),,$(CONFIG_PLATFORM))
obj-$(CONFIG_AIO_DW_COMPARATOR) += aio_dw_comparator.o aio_static_irq_stubs.o

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 2015 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <nanokernel.h>
#include <device.h>
#include <init.h>
#include <aio_comparator.h>
#include "aio_dw_comparator.h"
#define INT_COMPARATORS_MASK 0x7FFFF
static int dw_aio_cmp_config(struct device *dev)
{
ARG_UNUSED(dev);
IRQ_CONFIG(dw_aio_cmp, INT_AIO_CMP_IRQ, 0);
return DEV_OK;
}
static int dw_aio_cmp_disable(struct device *dev, uint8_t index)
{
struct dw_aio_cmp_dev_cfg_t *config =
(struct dw_aio_cmp_dev_cfg_t *)dev->config->config_info;
struct dw_aio_cmp_t *regs =
(struct dw_aio_cmp_t *)config->base_address;
if (index >= AIO_DW_CMP_COUNT) {
return DEV_INVALID_CONF;
}
/* Disable interrupt to host */
SCSS_INTERRUPT->int_comparators_host_mask |= (1 << index);
/* Disable comparator <index> */
regs->en &= ~(1 << index);
/* Disable power in comparator <index> */
regs->pwr &= ~(1 << index);
return DEV_OK;
}
static int dw_aio_cmp_configure(struct device *dev, uint8_t index,
enum aio_cmp_polarity polarity,
enum aio_cmp_ref refsel,
aio_cmp_cb cb, void *param)
{
struct dw_aio_cmp_dev_cfg_t *config =
(struct dw_aio_cmp_dev_cfg_t *)dev->config->config_info;
struct dw_aio_cmp_dev_data_t *dev_data =
(struct dw_aio_cmp_dev_data_t *)dev->driver_data;
struct dw_aio_cmp_t *regs =
(struct dw_aio_cmp_t *)config->base_address;
uint32_t reg_val;
/* index out of range */
if (index >= AIO_DW_CMP_COUNT) {
return DEV_INVALID_CONF;
}
/* make sure reference makes sense */
if ((refsel != AIO_CMP_REF_A) && (refsel != AIO_CMP_REF_B))
return DEV_INVALID_CONF;
/* make sure polarity makes sense */
if ((polarity != AIO_CMP_POL_RISE) && (polarity != AIO_CMP_POL_FALL))
return DEV_INVALID_CONF;
dev_data->cb[index].cb = cb;
dev_data->cb[index].param = param;
/* Disable interrupt to host */
SCSS_INTERRUPT->int_comparators_host_mask |= (1 << index);
/* Disable comparator <index> before config */
regs->en &= ~(1 << index);
regs->pwr &= ~(1 << index);
/**
* Setup reference voltage source
* REF_A: bit ==> 0, REF_B: bit ==> 1
*/
reg_val = regs->ref_sel;
if (refsel == AIO_CMP_REF_A)
reg_val &= ~(1 << index);
else
reg_val |= (1 << index);
regs->ref_sel = reg_val;
/**
* Setup reference polarity
* RISING: bit ==> 0, FALLING: bit ==> 1
*/
reg_val = regs->ref_pol;
if (polarity == AIO_CMP_POL_RISE)
reg_val &= ~(1 << index);
else
reg_val |= (1 << index);
regs->ref_pol = reg_val;
/* Enable power of comparator <index> */
regs->pwr |= (1 << index);
/* Enable comparator <index> */
regs->en |= (1 << index);
/* Enable interrupt to host */
SCSS_INTERRUPT->int_comparators_host_mask &= ~(1 << index);
return DEV_OK;
}
void dw_aio_cmp_isr(struct device *dev)
{
struct dw_aio_cmp_dev_cfg_t *config =
(struct dw_aio_cmp_dev_cfg_t *)dev->config->config_info;
struct dw_aio_cmp_dev_data_t *dev_data =
(struct dw_aio_cmp_dev_data_t *)dev->driver_data;
struct dw_aio_cmp_t *regs =
(struct dw_aio_cmp_t *)config->base_address;
int i;
int reg_stat_clr;
reg_stat_clr = regs->stat_clr;
for (i = 0; i < dev_data->num_cmp; i++) {
if (reg_stat_clr & (1 << i)) {
dw_aio_cmp_disable(dev, i);
if (dev_data->cb[i].cb != NULL) {
dev_data->cb[i].cb(dev_data->cb[i].param);
}
}
}
/* Clear interrupt status by writing 1s */
regs->stat_clr = reg_stat_clr;
}
static struct aio_cmp_driver_api dw_aio_cmp_funcs = {
.disable = dw_aio_cmp_disable,
.configure = dw_aio_cmp_configure,
};
int dw_aio_cmp_init(struct device *dev)
{
struct dw_aio_cmp_dev_cfg_t *config =
(struct dw_aio_cmp_dev_cfg_t *)dev->config->config_info;
struct dw_aio_cmp_dev_data_t *dev_data =
(struct dw_aio_cmp_dev_data_t *)dev->driver_data;
struct dw_aio_cmp_t *regs =
(struct dw_aio_cmp_t *)config->base_address;
int i;
if ((config->base_address == 0) || (config->interrupt_num == 0))
return DEV_INVALID_CONF;
if (config->config_func) {
i = config->config_func(dev);
if (i != DEV_OK)
return i;
}
dev->driver_api = &dw_aio_cmp_funcs;
/* Clear host interrupt mask */
SCSS_INTERRUPT->int_comparators_host_mask |= INT_COMPARATORS_MASK;
/* Clear comparator interrupt status */
regs->stat_clr |= INT_COMPARATORS_MASK;
/* Disable all comparators */
regs->en &= ~INT_COMPARATORS_MASK;
/* Power down all comparators */
regs->pwr &= ~INT_COMPARATORS_MASK;
/* Clear callback pointers */
for (i = 0; i < dev_data->num_cmp; i++) {
dev_data->cb[i].cb = NULL;
dev_data->cb[i].param = NULL;
}
irq_enable(config->interrupt_num);
return DEV_OK;
}
struct dw_aio_cmp_dev_cfg_t dw_aio_cmp_dev_config = {
.base_address = CONFIG_AIO_DW_COMPARATOR_BASE_ADDR,
.interrupt_num = INT_AIO_CMP_IRQ,
.config_func = dw_aio_cmp_config,
};
DECLARE_DEVICE_INIT_CONFIG(dw_aio_cmp,
AIO_DW_CMP_DRV_NAME,
&dw_aio_cmp_init,
&dw_aio_cmp_dev_config);
struct dw_aio_cmp_dev_data_t dw_aio_cmp_dev_data = {
.num_cmp = AIO_DW_CMP_COUNT,
};
micro_early_init(dw_aio_cmp, &dw_aio_cmp_dev_data);
struct device *dw_aio_cmp_device = SYS_GET_DEVICE(dw_aio_cmp);
IRQ_CONNECT_STATIC(dw_aio_cmp,
INT_AIO_CMP_IRQ,
0,
dw_aio_cmp_isr,
0);

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _AIO_DW_COMPARATOR_H_
#define _AIO_DW_COMPARATOR_H_
#include <board.h>
#include <device.h>
#include <aio_comparator.h>
#define AIO_DW_CMP_DRV_NAME "dw_aio_cmp"
/**
* @brief Number of AIO/Comparator on board
*/
#define AIO_DW_CMP_COUNT (19)
/**
* AIO/Comparator Register block type.
*/
struct dw_aio_cmp_t {
volatile uint32_t en; /**< Enable Register (0x00) */
volatile uint32_t ref_sel; /**< Reference Selection Register (0x04) */
volatile uint32_t ref_pol; /**< Reference Polarity Register (0x08) */
volatile uint32_t pwr; /**< Power Register (0x0C) */
uint32_t reversed[6];
volatile uint32_t stat_clr; /**< Status Clear Register (0x28) */
};
struct dw_aio_cmp_cb {
aio_cmp_cb cb;
void *param;
};
struct dw_aio_cmp_dev_cfg_t {
/** Base register address */
uint32_t base_address;
/** Interrupt number */
uint32_t interrupt_num;
/** Config function */
int (*config_func)(struct device *dev);
};
struct dw_aio_cmp_dev_data_t {
/** Number of total comparators */
uint8_t num_cmp;
/** Callback for each comparator */
struct dw_aio_cmp_cb cb[AIO_DW_CMP_COUNT];
};
#endif /* _AIO_DW_COMPARATOR_H_ */

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2015, Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @brief AIO interrupt stubs
* This module contains the static interrupt stubs for the aio driver
*/
#define _ASMLANGUAGE
#ifdef CONFIG_X86_32
#include <arch/x86/asm.h>
#include <drivers/ioapic.h>
#endif
#if defined(CONFIG_AIO_DW_COMPARATOR)
#if defined(CONFIG_IOAPIC)
ioapic_mkstub dw_aio_cmp dw_aio_cmp_isr dw_aio_cmp_device
#endif
#endif /* CONFIG_AIO_DW_COMPARATOR */

87
include/aio_comparator.h Normal file
View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2015 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _AIO_COMPARATOR_H_
#define _AIO_COMPARATOR_H_
enum aio_cmp_ref {
AIO_CMP_REF_A, /**< Use reference A. */
AIO_CMP_REF_B, /**< Use reference B. */
};
enum aio_cmp_polarity {
AIO_CMP_POL_RISE, /**< Match on rising edge. */
AIO_CMP_POL_FALL, /**< Match on falling edge. */
};
typedef void (*aio_cmp_cb)(void *);
typedef int (*aio_cmp_api_disable)(struct device *dev, uint8_t index);
typedef int (*aio_cmp_api_configure)(struct device *dev, uint8_t index,
enum aio_cmp_polarity polarity, enum aio_cmp_ref refsel,
aio_cmp_cb cb, void *param);
struct aio_cmp_driver_api {
aio_cmp_api_disable disable;
aio_cmp_api_configure configure;
};
/**
* @brief Disable a particular comparator.
*
* This disables a comparator so that it no longer triggers interrupts.
*
* @param dev Device struct
* @param index The index of the comparator to disable
*
* @return 0 if successful, otherwise failed.
*/
static inline int aio_cmp_disable(struct device *dev, uint8_t index)
{
struct aio_cmp_driver_api *api;
api = (struct aio_cmp_driver_api *)dev->driver_api;
return api->disable(dev, index);
}
/**
* @brief Configure and enable a particular comparator.
*
* This performs configuration and enable a comparator, so that it will
* generate interrupts when conditions are met.
*
* @param dev Device struct
* @param index The index of the comparator to disable
* @param polarity Match polarity (e.g. rising or falling)
* @param refsel Reference for trigger
* @param cb Function callback (aio_cmp_cb)
* @param param Parameters to be passed to callback
*
* @return 0 if successful, otherwise failed.
*/
static inline int aio_cmp_configure(struct device *dev, uint8_t index,
enum aio_cmp_polarity polarity,
enum aio_cmp_ref refsel,
aio_cmp_cb cb, void *param)
{
struct aio_cmp_driver_api *api;
api = (struct aio_cmp_driver_api *)dev->driver_api;
return api->configure(dev, index, polarity, refsel, cb, param);
}
#endif /* _AIO_COMPARATOR_H_ */