From 6d03a247468059b0e59c821ef39e6762d4d6fc30 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 23:00:51 +0200 Subject: Merging upstream version 6.9.2. Signed-off-by: Daniel Baumann --- drivers/i2c/busses/i2c-nomadik.c | 740 +++++++++++++++++++++++---------------- 1 file changed, 432 insertions(+), 308 deletions(-) (limited to 'drivers/i2c/busses/i2c-nomadik.c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index b10574d42b..4f41a3c782 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -6,21 +6,30 @@ * I2C master mode controller driver, used in Nomadik 8815 * and Ux500 platforms. * + * The Mobileye EyeQ5 platform is also supported; it uses + * the same Ux500/DB8500 IP block with two quirks: + * - The memory bus only supports 32-bit accesses. + * - A register must be configured for the I2C speed mode; + * it is located in a shared register region called OLB. + * * Author: Srinidhi Kasagar * Author: Sachin Verma */ -#include -#include #include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include #include -#include +#include +#include #include #include +#include +#include +#include #define DRIVER_NAME "nmk-i2c" @@ -42,61 +51,63 @@ #define I2C_ICR (0x038) /* Control registers */ -#define I2C_CR_PE (0x1 << 0) /* Peripheral Enable */ -#define I2C_CR_OM (0x3 << 1) /* Operating mode */ -#define I2C_CR_SAM (0x1 << 3) /* Slave addressing mode */ -#define I2C_CR_SM (0x3 << 4) /* Speed mode */ -#define I2C_CR_SGCM (0x1 << 6) /* Slave general call mode */ -#define I2C_CR_FTX (0x1 << 7) /* Flush Transmit */ -#define I2C_CR_FRX (0x1 << 8) /* Flush Receive */ -#define I2C_CR_DMA_TX_EN (0x1 << 9) /* DMA Tx enable */ -#define I2C_CR_DMA_RX_EN (0x1 << 10) /* DMA Rx Enable */ -#define I2C_CR_DMA_SLE (0x1 << 11) /* DMA sync. logic enable */ -#define I2C_CR_LM (0x1 << 12) /* Loopback mode */ -#define I2C_CR_FON (0x3 << 13) /* Filtering on */ -#define I2C_CR_FS (0x3 << 15) /* Force stop enable */ +#define I2C_CR_PE BIT(0) /* Peripheral Enable */ +#define I2C_CR_OM GENMASK(2, 1) /* Operating mode */ +#define I2C_CR_SAM BIT(3) /* Slave addressing mode */ +#define I2C_CR_SM GENMASK(5, 4) /* Speed mode */ +#define I2C_CR_SGCM BIT(6) /* Slave general call mode */ +#define I2C_CR_FTX BIT(7) /* Flush Transmit */ +#define I2C_CR_FRX BIT(8) /* Flush Receive */ +#define I2C_CR_DMA_TX_EN BIT(9) /* DMA Tx enable */ +#define I2C_CR_DMA_RX_EN BIT(10) /* DMA Rx Enable */ +#define I2C_CR_DMA_SLE BIT(11) /* DMA sync. logic enable */ +#define I2C_CR_LM BIT(12) /* Loopback mode */ +#define I2C_CR_FON GENMASK(14, 13) /* Filtering on */ +#define I2C_CR_FS GENMASK(16, 15) /* Force stop enable */ + +/* Slave control register (SCR) */ +#define I2C_SCR_SLSU GENMASK(31, 16) /* Slave data setup time */ /* Master controller (MCR) register */ -#define I2C_MCR_OP (0x1 << 0) /* Operation */ -#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */ -#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */ -#define I2C_MCR_SB (0x1 << 11) /* Extended address */ -#define I2C_MCR_AM (0x3 << 12) /* Address type */ -#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */ -#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */ +#define I2C_MCR_OP BIT(0) /* Operation */ +#define I2C_MCR_A7 GENMASK(7, 1) /* 7-bit address */ +#define I2C_MCR_EA10 GENMASK(10, 8) /* 10-bit Extended address */ +#define I2C_MCR_SB BIT(11) /* Extended address */ +#define I2C_MCR_AM GENMASK(13, 12) /* Address type */ +#define I2C_MCR_STOP BIT(14) /* Stop condition */ +#define I2C_MCR_LENGTH GENMASK(25, 15) /* Transaction length */ /* Status register (SR) */ -#define I2C_SR_OP (0x3 << 0) /* Operation */ -#define I2C_SR_STATUS (0x3 << 2) /* controller status */ -#define I2C_SR_CAUSE (0x7 << 4) /* Abort cause */ -#define I2C_SR_TYPE (0x3 << 7) /* Receive type */ -#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */ +#define I2C_SR_OP GENMASK(1, 0) /* Operation */ +#define I2C_SR_STATUS GENMASK(3, 2) /* controller status */ +#define I2C_SR_CAUSE GENMASK(6, 4) /* Abort cause */ +#define I2C_SR_TYPE GENMASK(8, 7) /* Receive type */ +#define I2C_SR_LENGTH GENMASK(19, 9) /* Transfer length */ + +/* Baud-rate counter register (BRCR) */ +#define I2C_BRCR_BRCNT1 GENMASK(31, 16) /* Baud-rate counter 1 */ +#define I2C_BRCR_BRCNT2 GENMASK(15, 0) /* Baud-rate counter 2 */ /* Interrupt mask set/clear (IMSCR) bits */ -#define I2C_IT_TXFE (0x1 << 0) -#define I2C_IT_TXFNE (0x1 << 1) -#define I2C_IT_TXFF (0x1 << 2) -#define I2C_IT_TXFOVR (0x1 << 3) -#define I2C_IT_RXFE (0x1 << 4) -#define I2C_IT_RXFNF (0x1 << 5) -#define I2C_IT_RXFF (0x1 << 6) -#define I2C_IT_RFSR (0x1 << 16) -#define I2C_IT_RFSE (0x1 << 17) -#define I2C_IT_WTSR (0x1 << 18) -#define I2C_IT_MTD (0x1 << 19) -#define I2C_IT_STD (0x1 << 20) -#define I2C_IT_MAL (0x1 << 24) -#define I2C_IT_BERR (0x1 << 25) -#define I2C_IT_MTDWS (0x1 << 28) - -#define GEN_MASK(val, mask, sb) (((val) << (sb)) & (mask)) +#define I2C_IT_TXFE BIT(0) +#define I2C_IT_TXFNE BIT(1) +#define I2C_IT_TXFF BIT(2) +#define I2C_IT_TXFOVR BIT(3) +#define I2C_IT_RXFE BIT(4) +#define I2C_IT_RXFNF BIT(5) +#define I2C_IT_RXFF BIT(6) +#define I2C_IT_RFSR BIT(16) +#define I2C_IT_RFSE BIT(17) +#define I2C_IT_WTSR BIT(18) +#define I2C_IT_MTD BIT(19) +#define I2C_IT_STD BIT(20) +#define I2C_IT_MAL BIT(24) +#define I2C_IT_BERR BIT(25) +#define I2C_IT_MTDWS BIT(28) /* some bits in ICR are reserved */ #define I2C_CLEAR_ALL_INTS 0x131f007f -/* first three msb bits are reserved */ -#define IRQ_MASK(mask) (mask & 0x1fffffff) - /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 @@ -107,6 +118,15 @@ enum i2c_freq_mode { I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ }; +/* Mobileye EyeQ5 offset into a shared register region (called OLB) */ +#define NMK_I2C_EYEQ5_OLB_IOCR2 0x0B8 + +enum i2c_eyeq5_speed { + I2C_EYEQ5_SPEED_FAST, + I2C_EYEQ5_SPEED_FAST_PLUS, + I2C_EYEQ5_SPEED_HIGH_SPEED, +}; + /** * struct i2c_vendor_data - per-vendor variations * @has_mtdws: variant has the MTDWS bit @@ -131,6 +151,12 @@ enum i2c_operation { I2C_READ = 0x01 }; +enum i2c_operating_mode { + I2C_OM_SLAVE, + I2C_OM_MASTER, + I2C_OM_MASTER_OR_SLAVE, +}; + /** * struct i2c_nmk_client - client specific data * @slave_adr: 7-bit slave address @@ -159,11 +185,13 @@ struct i2c_nmk_client { * @clk_freq: clock frequency for the operation mode * @tft: Tx FIFO Threshold in bytes * @rft: Rx FIFO Threshold in bytes - * @timeout: Slave response timeout (ms) + * @timeout_usecs: Slave response timeout * @sm: speed mode * @stop: stop condition. - * @xfer_complete: acknowledge completion for a I2C message. + * @xfer_wq: xfer done wait queue. + * @xfer_done: xfer done boolean. * @result: controller propogated result. + * @has_32b_bus: controller is on a bus that only supports 32-bit accesses. */ struct nmk_i2c_dev { struct i2c_vendor_data *vendor; @@ -176,11 +204,13 @@ struct nmk_i2c_dev { u32 clk_freq; unsigned char tft; unsigned char rft; - int timeout; + u32 timeout_usecs; enum i2c_freq_mode sm; int stop; - struct completion xfer_complete; + struct wait_queue_head xfer_wq; + bool xfer_done; int result; + bool has_32b_bus; }; /* controller's abort causes */ @@ -204,18 +234,36 @@ static inline void i2c_clr_bit(void __iomem *reg, u32 mask) writel(readl(reg) & ~mask, reg); } +static inline u8 nmk_i2c_readb(const struct nmk_i2c_dev *priv, + unsigned long reg) +{ + if (priv->has_32b_bus) + return readl(priv->virtbase + reg); + else + return readb(priv->virtbase + reg); +} + +static inline void nmk_i2c_writeb(const struct nmk_i2c_dev *priv, u32 val, + unsigned long reg) +{ + if (priv->has_32b_bus) + writel(val, priv->virtbase + reg); + else + writeb(val, priv->virtbase + reg); +} + /** * flush_i2c_fifo() - This function flushes the I2C FIFO - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver * * This function flushes the I2C Tx and Rx FIFOs. It returns * 0 on successful flushing of FIFO */ -static int flush_i2c_fifo(struct nmk_i2c_dev *dev) +static int flush_i2c_fifo(struct nmk_i2c_dev *priv) { #define LOOP_ATTEMPTS 10 + ktime_t timeout; int i; - unsigned long timeout; /* * flush the transmit and receive FIFO. The flushing @@ -224,19 +272,19 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) * bits, until then no one must access Tx, Rx FIFO and * should poll on these bits waiting for the completion. */ - writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR); + writel((I2C_CR_FTX | I2C_CR_FRX), priv->virtbase + I2C_CR); for (i = 0; i < LOOP_ATTEMPTS; i++) { - timeout = jiffies + dev->adap.timeout; + timeout = ktime_add_us(ktime_get(), priv->timeout_usecs); - while (!time_after(jiffies, timeout)) { - if ((readl(dev->virtbase + I2C_CR) & + while (ktime_after(timeout, ktime_get())) { + if ((readl(priv->virtbase + I2C_CR) & (I2C_CR_FTX | I2C_CR_FRX)) == 0) - return 0; + return 0; } } - dev_err(&dev->adev->dev, + dev_err(&priv->adev->dev, "flushing operation timed out giving up after %d attempts", LOOP_ATTEMPTS); @@ -245,120 +293,121 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) /** * disable_all_interrupts() - Disable all interrupts of this I2c Bus - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver */ -static void disable_all_interrupts(struct nmk_i2c_dev *dev) +static void disable_all_interrupts(struct nmk_i2c_dev *priv) { - u32 mask = IRQ_MASK(0); - writel(mask, dev->virtbase + I2C_IMSCR); + writel(0, priv->virtbase + I2C_IMSCR); } /** * clear_all_interrupts() - Clear all interrupts of I2C Controller - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver */ -static void clear_all_interrupts(struct nmk_i2c_dev *dev) +static void clear_all_interrupts(struct nmk_i2c_dev *priv) { - u32 mask; - mask = IRQ_MASK(I2C_CLEAR_ALL_INTS); - writel(mask, dev->virtbase + I2C_ICR); + writel(I2C_CLEAR_ALL_INTS, priv->virtbase + I2C_ICR); } /** * init_hw() - initialize the I2C hardware - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver */ -static int init_hw(struct nmk_i2c_dev *dev) +static int init_hw(struct nmk_i2c_dev *priv) { int stat; - stat = flush_i2c_fifo(dev); + stat = flush_i2c_fifo(priv); if (stat) goto exit; /* disable the controller */ - i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_clr_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - disable_all_interrupts(dev); + disable_all_interrupts(priv); - clear_all_interrupts(dev); + clear_all_interrupts(priv); - dev->cli.operation = I2C_NO_OPERATION; + priv->cli.operation = I2C_NO_OPERATION; exit: return stat; } /* enable peripheral, master mode operation */ -#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE) +#define DEFAULT_I2C_REG_CR (FIELD_PREP(I2C_CR_OM, I2C_OM_MASTER) | I2C_CR_PE) + +/* grab top three bits from extended I2C addresses */ +#define ADR_3MSB_BITS GENMASK(9, 7) /** * load_i2c_mcr_reg() - load the MCR register - * @dev: private data of controller + * @priv: private data of controller * @flags: message flags */ -static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags) +static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *priv, u16 flags) { u32 mcr = 0; unsigned short slave_adr_3msb_bits; - mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1); + mcr |= FIELD_PREP(I2C_MCR_A7, priv->cli.slave_adr); if (unlikely(flags & I2C_M_TEN)) { /* 10-bit address transaction */ - mcr |= GEN_MASK(2, I2C_MCR_AM, 12); + mcr |= FIELD_PREP(I2C_MCR_AM, 2); /* * Get the top 3 bits. * EA10 represents extended address in MCR. This includes * the extension (MSB bits) of the 7 bit address loaded * in A7 */ - slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7; + slave_adr_3msb_bits = FIELD_GET(ADR_3MSB_BITS, + priv->cli.slave_adr); - mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8); + mcr |= FIELD_PREP(I2C_MCR_EA10, slave_adr_3msb_bits); } else { /* 7-bit address transaction */ - mcr |= GEN_MASK(1, I2C_MCR_AM, 12); + mcr |= FIELD_PREP(I2C_MCR_AM, 1); } /* start byte procedure not applied */ - mcr |= GEN_MASK(0, I2C_MCR_SB, 11); + mcr |= FIELD_PREP(I2C_MCR_SB, 0); /* check the operation, master read/write? */ - if (dev->cli.operation == I2C_WRITE) - mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0); + if (priv->cli.operation == I2C_WRITE) + mcr |= FIELD_PREP(I2C_MCR_OP, I2C_WRITE); else - mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0); + mcr |= FIELD_PREP(I2C_MCR_OP, I2C_READ); /* stop or repeated start? */ - if (dev->stop) - mcr |= GEN_MASK(1, I2C_MCR_STOP, 14); + if (priv->stop) + mcr |= FIELD_PREP(I2C_MCR_STOP, 1); else - mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14)); + mcr &= ~FIELD_PREP(I2C_MCR_STOP, 1); - mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15); + mcr |= FIELD_PREP(I2C_MCR_LENGTH, priv->cli.count); return mcr; } /** * setup_i2c_controller() - setup the controller - * @dev: private data of controller + * @priv: private data of controller */ -static void setup_i2c_controller(struct nmk_i2c_dev *dev) +static void setup_i2c_controller(struct nmk_i2c_dev *priv) { u32 brcr1, brcr2; u32 i2c_clk, div; u32 ns; u16 slsu; - writel(0x0, dev->virtbase + I2C_CR); - writel(0x0, dev->virtbase + I2C_HSMCR); - writel(0x0, dev->virtbase + I2C_TFTR); - writel(0x0, dev->virtbase + I2C_RFTR); - writel(0x0, dev->virtbase + I2C_DMAR); + writel(0x0, priv->virtbase + I2C_CR); + writel(0x0, priv->virtbase + I2C_HSMCR); + writel(0x0, priv->virtbase + I2C_TFTR); + writel(0x0, priv->virtbase + I2C_RFTR); + writel(0x0, priv->virtbase + I2C_DMAR); - i2c_clk = clk_get_rate(dev->clk); + i2c_clk = clk_get_rate(priv->clk); /* * set the slsu: @@ -373,7 +422,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * slsu = cycles / (1000000000 / f) + 1 */ ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk); - switch (dev->sm) { + switch (priv->sm) { case I2C_FREQ_MODE_FAST: case I2C_FREQ_MODE_FAST_PLUS: slsu = DIV_ROUND_UP(100, ns); /* Fast */ @@ -388,15 +437,15 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) } slsu += 1; - dev_dbg(&dev->adev->dev, "calculated SLSU = %04x\n", slsu); - writel(slsu << 16, dev->virtbase + I2C_SCR); + dev_dbg(&priv->adev->dev, "calculated SLSU = %04x\n", slsu); + writel(FIELD_PREP(I2C_SCR_SLSU, slsu), priv->virtbase + I2C_SCR); /* * The spec says, in case of std. mode the divider is * 2 whereas it is 3 for fast and fastplus mode of * operation. TODO - high speed support. */ - div = (dev->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2; + div = (priv->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2; /* * generate the mask for baud rate counters. The controller @@ -405,11 +454,11 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * plus operation. Currently we do not supprt high speed mode * so set brcr1 to 0. */ - brcr1 = 0 << 16; - brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff; + brcr1 = FIELD_PREP(I2C_BRCR_BRCNT1, 0); + brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, i2c_clk / (priv->clk_freq * div)); /* set the baud rate counter register */ - writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); + writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR); /* * set the speed mode. Currently we support @@ -417,125 +466,142 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * TODO - support for fast mode plus (up to 1Mb/s) * and high speed (up to 3.4 Mb/s) */ - if (dev->sm > I2C_FREQ_MODE_FAST) { - dev_err(&dev->adev->dev, + if (priv->sm > I2C_FREQ_MODE_FAST) { + dev_err(&priv->adev->dev, "do not support this mode defaulting to std. mode\n"); - brcr2 = i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2) & 0xffff; - writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); - writel(I2C_FREQ_MODE_STANDARD << 4, - dev->virtbase + I2C_CR); + brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, + i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2)); + writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR); + writel(FIELD_PREP(I2C_CR_SM, I2C_FREQ_MODE_STANDARD), + priv->virtbase + I2C_CR); } - writel(dev->sm << 4, dev->virtbase + I2C_CR); + writel(FIELD_PREP(I2C_CR_SM, priv->sm), priv->virtbase + I2C_CR); /* set the Tx and Rx FIFO threshold */ - writel(dev->tft, dev->virtbase + I2C_TFTR); - writel(dev->rft, dev->virtbase + I2C_RFTR); + writel(priv->tft, priv->virtbase + I2C_TFTR); + writel(priv->rft, priv->virtbase + I2C_RFTR); +} + +static bool nmk_i2c_wait_xfer_done(struct nmk_i2c_dev *priv) +{ + if (priv->timeout_usecs < jiffies_to_usecs(1)) { + unsigned long timeout_usecs = priv->timeout_usecs; + ktime_t timeout = ktime_set(0, timeout_usecs * NSEC_PER_USEC); + + wait_event_hrtimeout(priv->xfer_wq, priv->xfer_done, timeout); + } else { + unsigned long timeout = usecs_to_jiffies(priv->timeout_usecs); + + wait_event_timeout(priv->xfer_wq, priv->xfer_done, timeout); + } + + return priv->xfer_done; } /** * read_i2c() - Read from I2C client device - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver * @flags: message flags * * This function reads from i2c client device when controller is in * master mode. There is a completion timeout. If there is no transfer * before timeout error is returned. */ -static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) +static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) { - int status = 0; u32 mcr, irq_mask; - unsigned long timeout; + int status = 0; + bool xfer_done; - mcr = load_i2c_mcr_reg(dev, flags); - writel(mcr, dev->virtbase + I2C_MCR); + mcr = load_i2c_mcr_reg(priv, flags); + writel(mcr, priv->virtbase + I2C_MCR); /* load the current CR value */ - writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, - dev->virtbase + I2C_CR); + writel(readl(priv->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, + priv->virtbase + I2C_CR); /* enable the controller */ - i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - init_completion(&dev->xfer_complete); + init_waitqueue_head(&priv->xfer_wq); + priv->xfer_done = false; /* enable interrupts by setting the mask */ irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF | I2C_IT_MAL | I2C_IT_BERR); - if (dev->stop || !dev->vendor->has_mtdws) + if (priv->stop || !priv->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; - irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask); + irq_mask &= I2C_CLEAR_ALL_INTS; - writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask, - dev->virtbase + I2C_IMSCR); + writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask, + priv->virtbase + I2C_IMSCR); - timeout = wait_for_completion_timeout( - &dev->xfer_complete, dev->adap.timeout); + xfer_done = nmk_i2c_wait_xfer_done(priv); - if (timeout == 0) { + if (!xfer_done) { /* Controller timed out */ - dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n", - dev->cli.slave_adr); + dev_err(&priv->adev->dev, "read from slave 0x%x timed out\n", + priv->cli.slave_adr); status = -ETIMEDOUT; } return status; } -static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) +static void fill_tx_fifo(struct nmk_i2c_dev *priv, int no_bytes) { int count; for (count = (no_bytes - 2); (count > 0) && - (dev->cli.count != 0); + (priv->cli.count != 0); count--) { /* write to the Tx FIFO */ - writeb(*dev->cli.buffer, - dev->virtbase + I2C_TFR); - dev->cli.buffer++; - dev->cli.count--; - dev->cli.xfer_bytes++; + nmk_i2c_writeb(priv, *priv->cli.buffer, I2C_TFR); + priv->cli.buffer++; + priv->cli.count--; + priv->cli.xfer_bytes++; } } /** * write_i2c() - Write data to I2C client. - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver * @flags: message flags * * This function writes data to I2C client */ -static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) +static int write_i2c(struct nmk_i2c_dev *priv, u16 flags) { - u32 status = 0; u32 mcr, irq_mask; - unsigned long timeout; + u32 status = 0; + bool xfer_done; - mcr = load_i2c_mcr_reg(dev, flags); + mcr = load_i2c_mcr_reg(priv, flags); - writel(mcr, dev->virtbase + I2C_MCR); + writel(mcr, priv->virtbase + I2C_MCR); /* load the current CR value */ - writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, - dev->virtbase + I2C_CR); + writel(readl(priv->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, + priv->virtbase + I2C_CR); /* enable the controller */ - i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - init_completion(&dev->xfer_complete); + init_waitqueue_head(&priv->xfer_wq); + priv->xfer_done = false; /* enable interrupts by settings the masks */ irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR); /* Fill the TX FIFO with transmit data */ - fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD); + fill_tx_fifo(priv, MAX_I2C_FIFO_THRESHOLD); - if (dev->cli.count != 0) + if (priv->cli.count != 0) irq_mask |= I2C_IT_TXFNE; /* @@ -543,23 +609,22 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) * set the MTDWS bit (Master Transaction Done Without Stop) * to start repeated start operation */ - if (dev->stop || !dev->vendor->has_mtdws) + if (priv->stop || !priv->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; - irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask); + irq_mask &= I2C_CLEAR_ALL_INTS; - writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask, - dev->virtbase + I2C_IMSCR); + writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask, + priv->virtbase + I2C_IMSCR); - timeout = wait_for_completion_timeout( - &dev->xfer_complete, dev->adap.timeout); + xfer_done = nmk_i2c_wait_xfer_done(priv); - if (timeout == 0) { + if (!xfer_done) { /* Controller timed out */ - dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n", - dev->cli.slave_adr); + dev_err(&priv->adev->dev, "write to slave 0x%x timed out\n", + priv->cli.slave_adr); status = -ETIMEDOUT; } @@ -568,44 +633,39 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) /** * nmk_i2c_xfer_one() - transmit a single I2C message - * @dev: device with a message encoded into it + * @priv: device with a message encoded into it * @flags: message flags */ -static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) +static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags) { int status; if (flags & I2C_M_RD) { /* read operation */ - dev->cli.operation = I2C_READ; - status = read_i2c(dev, flags); + priv->cli.operation = I2C_READ; + status = read_i2c(priv, flags); } else { /* write operation */ - dev->cli.operation = I2C_WRITE; - status = write_i2c(dev, flags); + priv->cli.operation = I2C_WRITE; + status = write_i2c(priv, flags); } - if (status || (dev->result)) { + if (status || priv->result) { u32 i2c_sr; u32 cause; - i2c_sr = readl(dev->virtbase + I2C_SR); - /* - * Check if the controller I2C operation status - * is set to ABORT(11b). - */ - if (((i2c_sr >> 2) & 0x3) == 0x3) { - /* get the abort cause */ - cause = (i2c_sr >> 4) & 0x7; - dev_err(&dev->adev->dev, "%s\n", + i2c_sr = readl(priv->virtbase + I2C_SR); + if (FIELD_GET(I2C_SR_STATUS, i2c_sr) == I2C_ABORT) { + cause = FIELD_GET(I2C_SR_CAUSE, i2c_sr); + dev_err(&priv->adev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); } - (void) init_hw(dev); + init_hw(priv); - status = status ? status : dev->result; + status = status ? status : priv->result; } return status; @@ -663,24 +723,24 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, { int status = 0; int i; - struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); + struct nmk_i2c_dev *priv = i2c_get_adapdata(i2c_adap); int j; - pm_runtime_get_sync(&dev->adev->dev); + pm_runtime_get_sync(&priv->adev->dev); /* Attempt three times to send the message queue */ for (j = 0; j < 3; j++) { /* setup the i2c controller */ - setup_i2c_controller(dev); + setup_i2c_controller(priv); for (i = 0; i < num_msgs; i++) { - dev->cli.slave_adr = msgs[i].addr; - dev->cli.buffer = msgs[i].buf; - dev->cli.count = msgs[i].len; - dev->stop = (i < (num_msgs - 1)) ? 0 : 1; - dev->result = 0; + priv->cli.slave_adr = msgs[i].addr; + priv->cli.buffer = msgs[i].buf; + priv->cli.count = msgs[i].len; + priv->stop = (i < (num_msgs - 1)) ? 0 : 1; + priv->result = 0; - status = nmk_i2c_xfer_one(dev, msgs[i].flags); + status = nmk_i2c_xfer_one(priv, msgs[i].flags); if (status != 0) break; } @@ -688,7 +748,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, break; } - pm_runtime_put_sync(&dev->adev->dev); + pm_runtime_put_sync(&priv->adev->dev); /* return the no. messages processed */ if (status) @@ -699,14 +759,14 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, /** * disable_interrupts() - disable the interrupts - * @dev: private data of controller + * @priv: private data of controller * @irq: interrupt number */ -static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq) +static int disable_interrupts(struct nmk_i2c_dev *priv, u32 irq) { - irq = IRQ_MASK(irq); - writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq), - dev->virtbase + I2C_IMSCR); + irq &= I2C_CLEAR_ALL_INTS; + writel(readl(priv->virtbase + I2C_IMSCR) & ~irq, + priv->virtbase + I2C_IMSCR); return 0; } @@ -723,38 +783,39 @@ static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq) */ static irqreturn_t i2c_irq_handler(int irq, void *arg) { - struct nmk_i2c_dev *dev = arg; + struct nmk_i2c_dev *priv = arg; + struct device *dev = &priv->adev->dev; u32 tft, rft; u32 count; u32 misr, src; /* load Tx FIFO and Rx FIFO threshold values */ - tft = readl(dev->virtbase + I2C_TFTR); - rft = readl(dev->virtbase + I2C_RFTR); + tft = readl(priv->virtbase + I2C_TFTR); + rft = readl(priv->virtbase + I2C_RFTR); /* read interrupt status register */ - misr = readl(dev->virtbase + I2C_MISR); + misr = readl(priv->virtbase + I2C_MISR); src = __ffs(misr); - switch ((1 << src)) { + switch (BIT(src)) { /* Transmit FIFO nearly empty interrupt */ case I2C_IT_TXFNE: { - if (dev->cli.operation == I2C_READ) { + if (priv->cli.operation == I2C_READ) { /* * in read operation why do we care for writing? * so disable the Transmit FIFO interrupt */ - disable_interrupts(dev, I2C_IT_TXFNE); + disable_interrupts(priv, I2C_IT_TXFNE); } else { - fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft)); + fill_tx_fifo(priv, (MAX_I2C_FIFO_THRESHOLD - tft)); /* * if done, close the transfer by disabling the * corresponding TXFNE interrupt */ - if (dev->cli.count == 0) - disable_interrupts(dev, I2C_IT_TXFNE); + if (priv->cli.count == 0) + disable_interrupts(priv, I2C_IT_TXFNE); } } break; @@ -768,60 +829,63 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_RXFNF: for (count = rft; count > 0; count--) { /* Read the Rx FIFO */ - *dev->cli.buffer = readb(dev->virtbase + I2C_RFR); - dev->cli.buffer++; + *priv->cli.buffer = nmk_i2c_readb(priv, I2C_RFR); + priv->cli.buffer++; } - dev->cli.count -= rft; - dev->cli.xfer_bytes += rft; + priv->cli.count -= rft; + priv->cli.xfer_bytes += rft; break; /* Rx FIFO full */ case I2C_IT_RXFF: for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) { - *dev->cli.buffer = readb(dev->virtbase + I2C_RFR); - dev->cli.buffer++; + *priv->cli.buffer = nmk_i2c_readb(priv, I2C_RFR); + priv->cli.buffer++; } - dev->cli.count -= MAX_I2C_FIFO_THRESHOLD; - dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD; + priv->cli.count -= MAX_I2C_FIFO_THRESHOLD; + priv->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD; break; /* Master Transaction Done with/without stop */ case I2C_IT_MTD: case I2C_IT_MTDWS: - if (dev->cli.operation == I2C_READ) { - while (!(readl(dev->virtbase + I2C_RISR) + if (priv->cli.operation == I2C_READ) { + while (!(readl(priv->virtbase + I2C_RISR) & I2C_IT_RXFE)) { - if (dev->cli.count == 0) + if (priv->cli.count == 0) break; - *dev->cli.buffer = - readb(dev->virtbase + I2C_RFR); - dev->cli.buffer++; - dev->cli.count--; - dev->cli.xfer_bytes++; + *priv->cli.buffer = + nmk_i2c_readb(priv, I2C_RFR); + priv->cli.buffer++; + priv->cli.count--; + priv->cli.xfer_bytes++; } } - disable_all_interrupts(dev); - clear_all_interrupts(dev); + disable_all_interrupts(priv); + clear_all_interrupts(priv); - if (dev->cli.count) { - dev->result = -EIO; - dev_err(&dev->adev->dev, - "%lu bytes still remain to be xfered\n", - dev->cli.count); - (void) init_hw(dev); + if (priv->cli.count) { + priv->result = -EIO; + dev_err(dev, "%lu bytes still remain to be xfered\n", + priv->cli.count); + init_hw(priv); } - complete(&dev->xfer_complete); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + break; /* Master Arbitration lost interrupt */ case I2C_IT_MAL: - dev->result = -EIO; - (void) init_hw(dev); + priv->result = -EIO; + init_hw(priv); + + i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_MAL); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL); - complete(&dev->xfer_complete); break; @@ -831,15 +895,20 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * during the transaction. */ case I2C_IT_BERR: - dev->result = -EIO; - /* get the status */ - if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT) - (void) init_hw(dev); + { + u32 sr; - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR); - complete(&dev->xfer_complete); + sr = readl(priv->virtbase + I2C_SR); + priv->result = -EIO; + if (FIELD_GET(I2C_SR_STATUS, sr) == I2C_ABORT) + init_hw(priv); - break; + i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_BERR); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + + } + break; /* * Tx FIFO overrun interrupt. @@ -847,11 +916,13 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * the Tx FIFO is full. */ case I2C_IT_TXFOVR: - dev->result = -EIO; - (void) init_hw(dev); + priv->result = -EIO; + init_hw(priv); + + dev_err(dev, "Tx Fifo Over run\n"); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); - dev_err(&dev->adev->dev, "Tx Fifo Over run\n"); - complete(&dev->xfer_complete); break; @@ -863,10 +934,10 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_RFSE: case I2C_IT_WTSR: case I2C_IT_STD: - dev_err(&dev->adev->dev, "unhandled Interrupt\n"); + dev_err(dev, "unhandled Interrupt\n"); break; default: - dev_err(&dev->adev->dev, "spurious Interrupt..\n"); + dev_err(dev, "spurious Interrupt..\n"); break; } @@ -893,9 +964,9 @@ static int nmk_i2c_resume_early(struct device *dev) static int nmk_i2c_runtime_suspend(struct device *dev) { struct amba_device *adev = to_amba_device(dev); - struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + struct nmk_i2c_dev *priv = amba_get_drvdata(adev); - clk_disable_unprepare(nmk_i2c->clk); + clk_disable_unprepare(priv->clk); pinctrl_pm_select_idle_state(dev); return 0; } @@ -903,10 +974,10 @@ static int nmk_i2c_runtime_suspend(struct device *dev) static int nmk_i2c_runtime_resume(struct device *dev) { struct amba_device *adev = to_amba_device(dev); - struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + struct nmk_i2c_dev *priv = amba_get_drvdata(adev); int ret; - ret = clk_prepare_enable(nmk_i2c->clk); + ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(dev, "can't prepare_enable clock\n"); return ret; @@ -914,9 +985,9 @@ static int nmk_i2c_runtime_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - ret = init_hw(nmk_i2c); + ret = init_hw(priv); if (ret) { - clk_disable_unprepare(nmk_i2c->clk); + clk_disable_unprepare(priv->clk); pinctrl_pm_select_idle_state(dev); } @@ -939,107 +1010,160 @@ static const struct i2c_algorithm nmk_i2c_algo = { }; static void nmk_i2c_of_probe(struct device_node *np, - struct nmk_i2c_dev *nmk) + struct nmk_i2c_dev *priv) { + u32 timeout_usecs; + /* Default to 100 kHz if no frequency is given in the node */ - if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq)) - nmk->clk_freq = I2C_MAX_STANDARD_MODE_FREQ; + if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) + priv->clk_freq = I2C_MAX_STANDARD_MODE_FREQ; /* This driver only supports 'standard' and 'fast' modes of operation. */ - if (nmk->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ) - nmk->sm = I2C_FREQ_MODE_STANDARD; + if (priv->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ) + priv->sm = I2C_FREQ_MODE_STANDARD; + else + priv->sm = I2C_FREQ_MODE_FAST; + priv->tft = 1; /* Tx FIFO threshold */ + priv->rft = 8; /* Rx FIFO threshold */ + + /* Slave response timeout */ + if (!of_property_read_u32(np, "i2c-transfer-timeout-us", &timeout_usecs)) + priv->timeout_usecs = timeout_usecs; + else + priv->timeout_usecs = 200 * USEC_PER_MSEC; +} + +static const unsigned int nmk_i2c_eyeq5_masks[] = { + GENMASK(5, 4), + GENMASK(7, 6), + GENMASK(9, 8), + GENMASK(11, 10), + GENMASK(13, 12), +}; + +static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv) +{ + struct device *dev = &priv->adev->dev; + struct device_node *np = dev->of_node; + unsigned int mask, speed_mode; + struct regmap *olb; + unsigned int id; + + priv->has_32b_bus = true; + + olb = syscon_regmap_lookup_by_phandle_args(np, "mobileye,olb", 1, &id); + if (IS_ERR(olb)) + return PTR_ERR(olb); + if (id >= ARRAY_SIZE(nmk_i2c_eyeq5_masks)) + return -ENOENT; + + if (priv->clk_freq <= 400000) + speed_mode = I2C_EYEQ5_SPEED_FAST; + else if (priv->clk_freq <= 1000000) + speed_mode = I2C_EYEQ5_SPEED_FAST_PLUS; else - nmk->sm = I2C_FREQ_MODE_FAST; - nmk->tft = 1; /* Tx FIFO threshold */ - nmk->rft = 8; /* Rx FIFO threshold */ - nmk->timeout = 200; /* Slave response timeout(ms) */ + speed_mode = I2C_EYEQ5_SPEED_HIGH_SPEED; + + mask = nmk_i2c_eyeq5_masks[id]; + regmap_update_bits(olb, NMK_I2C_EYEQ5_OLB_IOCR2, + mask, speed_mode << __fls(mask)); + + return 0; } static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; + struct nmk_i2c_dev *priv; struct device_node *np = adev->dev.of_node; - struct nmk_i2c_dev *dev; + struct device *dev = &adev->dev; struct i2c_adapter *adap; struct i2c_vendor_data *vendor = id->data; u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; - dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - dev->vendor = vendor; - dev->adev = adev; - nmk_i2c_of_probe(np, dev); + priv->vendor = vendor; + priv->adev = adev; + priv->has_32b_bus = false; + nmk_i2c_of_probe(np, priv); + + if (of_device_is_compatible(np, "mobileye,eyeq5-i2c")) { + ret = nmk_i2c_eyeq5_probe(priv); + if (ret) + return dev_err_probe(dev, ret, "failed OLB lookup\n"); + } - if (dev->tft > max_fifo_threshold) { - dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n", - dev->tft, max_fifo_threshold); - dev->tft = max_fifo_threshold; + if (priv->tft > max_fifo_threshold) { + dev_warn(dev, "requested TX FIFO threshold %u, adjusted down to %u\n", + priv->tft, max_fifo_threshold); + priv->tft = max_fifo_threshold; } - if (dev->rft > max_fifo_threshold) { - dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n", - dev->rft, max_fifo_threshold); - dev->rft = max_fifo_threshold; + if (priv->rft > max_fifo_threshold) { + dev_warn(dev, "requested RX FIFO threshold %u, adjusted down to %u\n", + priv->rft, max_fifo_threshold); + priv->rft = max_fifo_threshold; } - amba_set_drvdata(adev, dev); + amba_set_drvdata(adev, priv); - dev->virtbase = devm_ioremap(&adev->dev, adev->res.start, - resource_size(&adev->res)); - if (!dev->virtbase) + priv->virtbase = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (!priv->virtbase) return -ENOMEM; - dev->irq = adev->irq[0]; - ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0, - DRIVER_NAME, dev); + priv->irq = adev->irq[0]; + ret = devm_request_irq(dev, priv->irq, i2c_irq_handler, 0, + DRIVER_NAME, priv); if (ret) - return dev_err_probe(&adev->dev, ret, - "cannot claim the irq %d\n", dev->irq); + return dev_err_probe(dev, ret, + "cannot claim the irq %d\n", priv->irq); - dev->clk = devm_clk_get_enabled(&adev->dev, NULL); - if (IS_ERR(dev->clk)) - return dev_err_probe(&adev->dev, PTR_ERR(dev->clk), + priv->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "could enable i2c clock\n"); - init_hw(dev); + init_hw(priv); - adap = &dev->adap; + adap = &priv->adap; adap->dev.of_node = np; - adap->dev.parent = &adev->dev; + adap->dev.parent = dev; adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; adap->algo = &nmk_i2c_algo; - adap->timeout = msecs_to_jiffies(dev->timeout); + adap->timeout = usecs_to_jiffies(priv->timeout_usecs); snprintf(adap->name, sizeof(adap->name), "Nomadik I2C at %pR", &adev->res); - i2c_set_adapdata(adap, dev); + i2c_set_adapdata(adap, priv); - dev_info(&adev->dev, + dev_info(dev, "initialize %s on virtual base %p\n", - adap->name, dev->virtbase); + adap->name, priv->virtbase); ret = i2c_add_adapter(adap); if (ret) return ret; - pm_runtime_put(&adev->dev); + pm_runtime_put(dev); return 0; } static void nmk_i2c_remove(struct amba_device *adev) { - struct nmk_i2c_dev *dev = amba_get_drvdata(adev); + struct nmk_i2c_dev *priv = amba_get_drvdata(adev); - i2c_del_adapter(&dev->adap); - flush_i2c_fifo(dev); - disable_all_interrupts(dev); - clear_all_interrupts(dev); + i2c_del_adapter(&priv->adap); + flush_i2c_fifo(priv); + disable_all_interrupts(priv); + clear_all_interrupts(priv); /* disable the controller */ - i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_clr_bit(priv->virtbase + I2C_CR, I2C_CR_PE); } static struct i2c_vendor_data vendor_stn8815 = { -- cgit v1.2.3