/*
* Xilinx XADC driver
*
* Copyright 2013-2014 Analog Devices Inc.
* Author: Lars-Peter Clauen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*
* Documentation for the parts can be found at:
* - XADC hardmacro: Xilinx UG480
* - ZYNQ XADC interface: Xilinx UG585
* - AXI XADC interface: Xilinx PG019
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "xilinx-xadc.h"
static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500;
/* ZYNQ register definitions */
#define XADC_ZYNQ_REG_CFG 0x00
#define XADC_ZYNQ_REG_INTSTS 0x04
#define XADC_ZYNQ_REG_INTMSK 0x08
#define XADC_ZYNQ_REG_STATUS 0x0c
#define XADC_ZYNQ_REG_CFIFO 0x10
#define XADC_ZYNQ_REG_DFIFO 0x14
#define XADC_ZYNQ_REG_CTL 0x18
#define XADC_ZYNQ_CFG_ENABLE BIT(31)
#define XADC_ZYNQ_CFG_CFIFOTH_MASK (0xf << 20)
#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET 20
#define XADC_ZYNQ_CFG_DFIFOTH_MASK (0xf << 16)
#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET 16
#define XADC_ZYNQ_CFG_WEDGE BIT(13)
#define XADC_ZYNQ_CFG_REDGE BIT(12)
#define XADC_ZYNQ_CFG_TCKRATE_MASK (0x3 << 8)
#define XADC_ZYNQ_CFG_TCKRATE_DIV2 (0x0 << 8)
#define XADC_ZYNQ_CFG_TCKRATE_DIV4 (0x1 << 8)
#define XADC_ZYNQ_CFG_TCKRATE_DIV8 (0x2 << 8)
#define XADC_ZYNQ_CFG_TCKRATE_DIV16 (0x3 << 8)
#define XADC_ZYNQ_CFG_IGAP_MASK 0x1f
#define XADC_ZYNQ_CFG_IGAP(x) (x)
#define XADC_ZYNQ_INT_CFIFO_LTH BIT(9)
#define XADC_ZYNQ_INT_DFIFO_GTH BIT(8)
#define XADC_ZYNQ_INT_ALARM_MASK 0xff
#define XADC_ZYNQ_INT_ALARM_OFFSET 0
#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK (0xf << 16)
#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET 16
#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK (0xf << 12)
#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET 12
#define XADC_ZYNQ_STATUS_CFIFOF BIT(11)
#define XADC_ZYNQ_STATUS_CFIFOE BIT(10)
#define XADC_ZYNQ_STATUS_DFIFOF BIT(9)
#define XADC_ZYNQ_STATUS_DFIFOE BIT(8)
#define XADC_ZYNQ_STATUS_OT BIT(7)
#define XADC_ZYNQ_STATUS_ALM(x) BIT(x)
#define XADC_ZYNQ_CTL_RESET BIT(4)
#define XADC_ZYNQ_CMD_NOP 0x00
#define XADC_ZYNQ_CMD_READ 0x01
#define XADC_ZYNQ_CMD_WRITE 0x02
#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (data))
/* AXI register definitions */
#define XADC_AXI_REG_RESET 0x00
#define XADC_AXI_REG_STATUS 0x04
#define XADC_AXI_REG_ALARM_STATUS 0x08
#define XADC_AXI_REG_CONVST 0x0c
#define XADC_AXI_REG_XADC_RESET 0x10
#define XADC_AXI_REG_GIER 0x5c
#define XADC_AXI_REG_IPISR 0x60
#define XADC_AXI_REG_IPIER 0x68
#define XADC_AXI_ADC_REG_OFFSET 0x200
#define XADC_AXI_RESET_MAGIC 0xa
#define XADC_AXI_GIER_ENABLE BIT(31)
#define XADC_AXI_INT_EOS BIT(4)
#define XADC_AXI_INT_ALARM_MASK 0x3c0f
#define XADC_FLAGS_BUFFERED BIT(0)
static void xadc_write_reg(struct xadc *xadc, unsigned int reg,
uint32_t val)
{
writel(val, xadc->base + reg);
}
static void xadc_read_reg(struct xadc *xadc, unsigned int reg,
uint32_t *val)
{
*val = readl(xadc->base + reg);
}
/*
* The ZYNQ interface uses two asynchronous FIFOs for communication with the
* XADC. Reads and writes to the XADC register are performed by submitting a
* request to the command FIFO (CFIFO), once the request has been completed the
* result can be read from the data FIFO (DFIFO). The method currently used in
* this driver is to submit the request for a read/write operation, then go to
* sleep and wait for an interrupt that signals that a response is available in
* the data FIFO.
*/
static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd,
unsigned int n)
{
unsigned int i;
for (i = 0; i < n; i++)
xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]);
}
static void xadc_zynq_drain_fifo(struct xadc *xadc)
{
uint32_t status, tmp;
xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status);
while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) {
xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO,