diff --git a/drivers/Kconfig b/drivers/Kconfig index 9448456b3c4..c33747e62df 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -61,4 +61,6 @@ source "drivers/clock_control/Kconfig" source "drivers/ipi/Kconfig" +source "drivers/aio/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 9495d07ce11..79222cb0669 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_RTC) += rtc/ obj-$(CONFIG_CLOCK_CONTROL) += clock_control/ obj-$(CONFIG_IPI) += ipi/ +obj-y += aio/ diff --git a/drivers/aio/Kconfig b/drivers/aio/Kconfig new file mode 100644 index 00000000000..6ea175d4f9c --- /dev/null +++ b/drivers/aio/Kconfig @@ -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. + diff --git a/drivers/aio/Makefile b/drivers/aio/Makefile new file mode 100644 index 00000000000..b9ba574477c --- /dev/null +++ b/drivers/aio/Makefile @@ -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 diff --git a/drivers/aio/aio_dw_comparator.c b/drivers/aio/aio_dw_comparator.c new file mode 100644 index 00000000000..55a43465493 --- /dev/null +++ b/drivers/aio/aio_dw_comparator.c @@ -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 + +#include +#include +#include +#include + +#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 */ + regs->en &= ~(1 << index); + /* Disable power in comparator */ + 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 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 */ + regs->pwr |= (1 << index); + + /* Enable comparator */ + 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); + diff --git a/drivers/aio/aio_dw_comparator.h b/drivers/aio/aio_dw_comparator.h new file mode 100644 index 00000000000..3283a59173a --- /dev/null +++ b/drivers/aio/aio_dw_comparator.h @@ -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 +#include +#include + +#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_ */ diff --git a/drivers/aio/aio_static_irq_stubs.S b/drivers/aio/aio_static_irq_stubs.S new file mode 100644 index 00000000000..456b8a4c9ad --- /dev/null +++ b/drivers/aio/aio_static_irq_stubs.S @@ -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 +#include +#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 */ diff --git a/include/aio_comparator.h b/include/aio_comparator.h new file mode 100644 index 00000000000..ec667e942a2 --- /dev/null +++ b/include/aio_comparator.h @@ -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_ */