/* * Copyright (C) 2019 CERN (www.cern.ch) * Author: Miguel Jimenez Lopez * * Released according to the GNU GPL, version 2 or any later version. * * This work is part of the White Rabbit project, a research effort led * by CERN, the European Institute for Nuclear Research. */ #ifdef __KERNEL__ #include #include #include #include #include //FIXME: Back hack to maintain the IOCTL command numbers #include #include "hw/wr-dio-regs.h" #include "hw/ppsg-regs.h" /* Forward declaration */ struct fmc_dio; /* This is somehow generic, but I find no better place at this time */ #ifndef SET_HI32 # if BITS_PER_LONG > 32 # define SET_HI32(var, value) ((var) |= (long)(value) << 32) # define GET_HI32(var) ((var) >> 32) # else # define SET_HI32(var, value) ((var) |= 0) # define GET_HI32(var) 0 # endif #endif /* For GPIO we have no wb-gen header */ struct fmc_dio_gpio_block { uint32_t clear; uint32_t set; uint32_t dir; uint32_t status; }; /* And this is our bit mapping */ #define FMC_DIO_GPIO_VALUE(bit) (1 << ((4 * (bit)) + 0)) /* FMC DIO name string pattern */ #define FMC_DIO_NAME_PATTERN "fmc-dio-%d:%d" /* Size of the name field of the fmc_dio structure */ #define FMC_DIO_NAME_MAX 20 /* Board constants */ #define FMC_DIO_BOARD_SPEC 0 #define FMC_DIOv2_BOARD_SPEC 1 /** * @brief FMC DIO structure * * This contains information regarding FMC DIO. */ struct fmc_dio { char name[FMC_DIO_NAME_MAX]; /**< Name of the FMC DIO */ struct miscdevice mdev; /**< Linux Miscdevice for the FMC DIO */ struct platform_device *pdev; /**< Linux platform_device for the FMC DIO */ struct fmc_device *fmc; /** FMC device for the FMC DIO */ struct gpio_chip *gc; /**< Linux GPIO chip */ void __iomem *dio; /**< DIO IP block pointer */ void __iomem *gpio; /**< GPIO IP block pointer */ void __iomem *ppsg; /**< PPSG IP block pointer */ const char *irqdomain_name; /**< IRQ domain name */ int irq; /**< IRQ number for DIO FMC */ int board; /**< Board info */ int version; //*< HDL version */ void *priv; /**< Private data for FMC DIO */ }; // From fmc-dio-internal.c extern irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev); extern int fmc_dio_int_ioctl(struct fmc_dio *dev, unsigned int ioctlcmd, unsigned long arg); extern int fmc_dio_internal_create(struct fmc_dio *dev); extern void fmc_dio_internal_destroy(struct fmc_dio *dev); // From fmc-dio-mdev.c extern int fmc_dio_mdev_create(struct fmc_dio *dio); extern void fmc_dio_mdev_destroy(struct fmc_dio *dio); // From fmc-dio-gpio.c extern int fmc_dio_gpio_init(struct fmc_dio *dev); extern void fmc_dio_gpio_exit(struct fmc_dio *dev); #endif /* __KERNEL__ */ // FIXME: Move IOCTL command numbers? #define PRIV_MEZZANINE_ID (SIOCDEVPRIVATE + 14) #define PRIV_MEZZANINE_CMD (SIOCDEVPRIVATE + 15) // FMC DIO Commands enum wr_dio_cmd_name { WR_DIO_CMD_PULSE, WR_DIO_CMD_STAMP, WR_DIO_CMD_DAC, WR_DIO_CMD_INOUT, WR_DIO_CMD_IRQ, WR_DIO_CMD_UPDATE_WIDTH, WR_DIO_CMD_MASK_IRQ, }; /* * This is how parameters are used (K == reply from kernel): * * CMD_PULSE: * cmd->flags: F_NOW, F_REL, F_LOOP * cmd->channel: the channel or the mask * cmd->t[]: either 2 or 3 values (start, duration, loop) * cmd->value: count of loops (0 to turn off) * * CMD_STAMP: * cmd->flags: F_MASK, F_WAIT * cmd->channel: the channel or the mask * K: cmd->channel: the channel where we had stamps * K: cmd->nstamp: number of valid stamps * K: cmd->t[]: the stamps * * CMD_DAC: * cmd->flags: none * cmd->channel: which one * cmd->value: the value * * CMD_INOUT: * cmd->flags: F_MASK * cmd->channel: the channel or the mask * cmd->value: bits 0..4: WR-DIO, 8..12 value, 16..20 OEN, 24..28 term * */ #define WR_DIO_INOUT_DIO (1 << 0) #define WR_DIO_INOUT_VALUE (1 << 8) #define WR_DIO_INOUT_OUTPUT (1 << 16) #define WR_DIO_INOUT_TERM (1 << 24) #define WR_DIO_N_STAMP 16 /* At least 5 * 3 */ struct wr_timestamp_info { uint16_t leap_second; int leap_second_valid; int flag59; int flag61; }; struct wr_dio_cmd { uint16_t command; /* from user */ uint16_t channel; /* 0..4 or mask from user */ uint32_t value; /* for DAC or I/O */ uint32_t flags; uint32_t nstamp; /* from kernel, if IN_STAMP */ struct timespec t[WR_DIO_N_STAMP]; struct wr_timestamp_info wr_ts_info_buf[WR_DIO_N_STAMP]; uint32_t wait_mode_flags; struct timespec wait_mode_timeout; }; #define WR_DIO_F_NOW 0x01 /* Output is now, t[0] ignored */ #define WR_DIO_F_REL 0x02 /* t[0].tv_sec is relative */ #define WR_DIO_F_MASK 0x04 /* Channel is 0x00..0x1f */ #define WR_DIO_F_LOOP 0x08 /* Output should loop: t[2] is looping*/ #define WR_DIO_F_WAIT 0x10 /* Wait for event */ #define WR_DIO_F_MASK_READ_IRQ 0x20 #define WR_DIO_F_MASK_ENABLE_IRQ 0x40 #define WR_DIO_F_MASK_DISABLE_IRQ 0x80 #define WR_DIO_F_WAIT_MODE_NORM 0x00 #define WR_DIO_F_WAIT_MODE_TIMEOUT 0x01