18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/i2c.h> 88c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_CR 0x00 /* control register */ 158c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_CR_MST BIT(3) /* master mode */ 168c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_CR_STA BIT(2) /* start condition */ 178c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_CR_STO BIT(1) /* stop condition */ 188c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_CR_NACK BIT(0) /* do not return ACK */ 198c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_DTTX 0x04 /* TX FIFO */ 208c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (slave addr) */ 218c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_DTTX_RD BIT(0) /* read transaction */ 228c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_DTRX 0x04 /* RX FIFO */ 238c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SLAD 0x0c /* slave address */ 248c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_CYC 0x10 /* clock cycle control */ 258c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_LCTL 0x14 /* clock low period control */ 268c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SSUT 0x18 /* restart/stop setup time control */ 278c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_DSUT 0x1c /* data setup time control */ 288c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT 0x20 /* interrupt status */ 298c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_IE 0x24 /* interrupt enable */ 308c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_IC 0x28 /* interrupt clear */ 318c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_TE BIT(9) /* TX FIFO empty */ 328c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_RF BIT(8) /* RX FIFO full */ 338c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_TC BIT(7) /* send complete (STOP) */ 348c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_RC BIT(6) /* receive complete (STOP) */ 358c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_TB BIT(5) /* sent specified bytes */ 368c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_RB BIT(4) /* received specified bytes */ 378c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_NA BIT(2) /* no ACK */ 388c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_AL BIT(1) /* arbitration lost */ 398c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR 0x2c /* status register */ 408c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_DB BIT(12) /* device busy */ 418c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_STS BIT(11) /* stop condition detected */ 428c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_BB BIT(8) /* bus busy */ 438c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_RFF BIT(3) /* RX FIFO full */ 448c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_RNE BIT(2) /* RX FIFO not empty */ 458c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_TNF BIT(1) /* TX FIFO not full */ 468c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_SR_TFE BIT(0) /* TX FIFO empty */ 478c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RST 0x34 /* reset control */ 488c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RST_TBRST BIT(2) /* clear TX FIFO */ 498c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RST_RBRST BIT(1) /* clear RX FIFO */ 508c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RST_RST BIT(0) /* forcible bus reset */ 518c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BM 0x38 /* bus monitor */ 528c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BM_SDAO BIT(3) /* output for SDA line */ 538c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BM_SDAS BIT(2) /* readback of SDA line */ 548c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BM_SCLO BIT(1) /* output for SCL line */ 558c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BM_SCLS BIT(0) /* readback of SCL line */ 568c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_NOISE 0x3c /* noise filter control */ 578c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_TBC 0x40 /* TX byte count setting */ 588c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RBC 0x44 /* RX byte count setting */ 598c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_TBCM 0x48 /* TX byte count monitor */ 608c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RBCM 0x4c /* RX byte count monitor */ 618c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BRST 0x50 /* bus reset */ 628c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BRST_FOEN BIT(1) /* normal operation */ 638c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BRST_RSCL BIT(0) /* release SCL */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_FAULTS \ 668c2ecf20Sopenharmony_ci (UNIPHIER_FI2C_INT_NA | UNIPHIER_FI2C_INT_AL) 678c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_INT_STOP \ 688c2ecf20Sopenharmony_ci (UNIPHIER_FI2C_INT_TC | UNIPHIER_FI2C_INT_RC) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_RD BIT(0) 718c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_STOP BIT(1) 728c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_MANUAL_NACK BIT(2) 738c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_BYTE_WISE BIT(3) 748c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_DEFER_STOP_COMP BIT(4) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define UNIPHIER_FI2C_FIFO_SIZE 8 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct uniphier_fi2c_priv { 798c2ecf20Sopenharmony_ci struct completion comp; 808c2ecf20Sopenharmony_ci struct i2c_adapter adap; 818c2ecf20Sopenharmony_ci void __iomem *membase; 828c2ecf20Sopenharmony_ci struct clk *clk; 838c2ecf20Sopenharmony_ci unsigned int len; 848c2ecf20Sopenharmony_ci u8 *buf; 858c2ecf20Sopenharmony_ci u32 enabled_irqs; 868c2ecf20Sopenharmony_ci int error; 878c2ecf20Sopenharmony_ci unsigned int flags; 888c2ecf20Sopenharmony_ci unsigned int busy_cnt; 898c2ecf20Sopenharmony_ci unsigned int clk_cycle; 908c2ecf20Sopenharmony_ci spinlock_t lock; /* IRQ synchronization */ 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv, 948c2ecf20Sopenharmony_ci bool first) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci int fifo_space = UNIPHIER_FI2C_FIFO_SIZE; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * TX-FIFO stores slave address in it for the first access. 1008c2ecf20Sopenharmony_ci * Decrement the counter. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci if (first) 1038c2ecf20Sopenharmony_ci fifo_space--; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci while (priv->len) { 1068c2ecf20Sopenharmony_ci if (fifo_space-- <= 0) 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX); 1108c2ecf20Sopenharmony_ci priv->len--; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ? 1178c2ecf20Sopenharmony_ci 1 : UNIPHIER_FI2C_FIFO_SIZE; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci while (priv->len) { 1208c2ecf20Sopenharmony_ci if (fifo_left-- <= 0) 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci *priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX); 1248c2ecf20Sopenharmony_ci priv->len--; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv, 1348c2ecf20Sopenharmony_ci u32 mask) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci writel(mask, priv->membase + UNIPHIER_FI2C_IC); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP; 1428c2ecf20Sopenharmony_ci uniphier_fi2c_set_irqs(priv); 1438c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO, 1448c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_CR); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = dev_id; 1508c2ecf20Sopenharmony_ci u32 irq_status; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci irq_status = readl(priv->membase + UNIPHIER_FI2C_INT); 1558c2ecf20Sopenharmony_ci irq_status &= priv->enabled_irqs; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (irq_status & UNIPHIER_FI2C_INT_STOP) 1588c2ecf20Sopenharmony_ci goto complete; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) { 1618c2ecf20Sopenharmony_ci priv->error = -EAGAIN; 1628c2ecf20Sopenharmony_ci goto complete; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) { 1668c2ecf20Sopenharmony_ci priv->error = -ENXIO; 1678c2ecf20Sopenharmony_ci if (priv->flags & UNIPHIER_FI2C_RD) { 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * work around a hardware bug: 1708c2ecf20Sopenharmony_ci * The receive-completed interrupt is never set even if 1718c2ecf20Sopenharmony_ci * STOP condition is detected after the address phase 1728c2ecf20Sopenharmony_ci * of read transaction fails to get ACK. 1738c2ecf20Sopenharmony_ci * To avoid time-out error, we issue STOP here, 1748c2ecf20Sopenharmony_ci * but do not wait for its completion. 1758c2ecf20Sopenharmony_ci * It should be checked after exiting this handler. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci uniphier_fi2c_stop(priv); 1788c2ecf20Sopenharmony_ci priv->flags |= UNIPHIER_FI2C_DEFER_STOP_COMP; 1798c2ecf20Sopenharmony_ci goto complete; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci goto stop; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (irq_status & UNIPHIER_FI2C_INT_TE) { 1858c2ecf20Sopenharmony_ci if (!priv->len) 1868c2ecf20Sopenharmony_ci goto data_done; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci uniphier_fi2c_fill_txfifo(priv, false); 1898c2ecf20Sopenharmony_ci goto handled; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) { 1938c2ecf20Sopenharmony_ci uniphier_fi2c_drain_rxfifo(priv); 1948c2ecf20Sopenharmony_ci /* 1958c2ecf20Sopenharmony_ci * If the number of bytes to read is multiple of the FIFO size 1968c2ecf20Sopenharmony_ci * (msg->len == 8, 16, 24, ...), the INT_RF bit is set a little 1978c2ecf20Sopenharmony_ci * earlier than INT_RB. We wait for INT_RB to confirm the 1988c2ecf20Sopenharmony_ci * completion of the current message. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci if (!priv->len && (irq_status & UNIPHIER_FI2C_INT_RB)) 2018c2ecf20Sopenharmony_ci goto data_done; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) { 2048c2ecf20Sopenharmony_ci if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE && 2058c2ecf20Sopenharmony_ci !(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) { 2068c2ecf20Sopenharmony_ci priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB; 2078c2ecf20Sopenharmony_ci uniphier_fi2c_set_irqs(priv); 2088c2ecf20Sopenharmony_ci priv->flags |= UNIPHIER_FI2C_BYTE_WISE; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci if (priv->len <= 1) 2118c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_CR_MST | 2128c2ecf20Sopenharmony_ci UNIPHIER_FI2C_CR_NACK, 2138c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_CR); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci goto handled; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return IRQ_NONE; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cidata_done: 2248c2ecf20Sopenharmony_ci if (priv->flags & UNIPHIER_FI2C_STOP) { 2258c2ecf20Sopenharmony_cistop: 2268c2ecf20Sopenharmony_ci uniphier_fi2c_stop(priv); 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_cicomplete: 2298c2ecf20Sopenharmony_ci priv->enabled_irqs = 0; 2308c2ecf20Sopenharmony_ci uniphier_fi2c_set_irqs(priv); 2318c2ecf20Sopenharmony_ci complete(&priv->comp); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cihandled: 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * This controller makes a pause while any bit of the IRQ status is 2378c2ecf20Sopenharmony_ci * asserted. Clear the asserted bit to kick the controller just before 2388c2ecf20Sopenharmony_ci * exiting the handler. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci uniphier_fi2c_clear_irqs(priv, irq_status); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr, 2488c2ecf20Sopenharmony_ci bool repeat) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE; 2518c2ecf20Sopenharmony_ci uniphier_fi2c_set_irqs(priv); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* do not use TX byte counter */ 2548c2ecf20Sopenharmony_ci writel(0, priv->membase + UNIPHIER_FI2C_TBC); 2558c2ecf20Sopenharmony_ci /* set slave address */ 2568c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1, 2578c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_DTTX); 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * First chunk of data. For a repeated START condition, do not write 2608c2ecf20Sopenharmony_ci * data to the TX fifo here to avoid the timing issue. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci if (!repeat) 2638c2ecf20Sopenharmony_ci uniphier_fi2c_fill_txfifo(priv, true); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci priv->flags |= UNIPHIER_FI2C_RD; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (likely(priv->len < 256)) { 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * If possible, use RX byte counter. 2738c2ecf20Sopenharmony_ci * It can automatically handle NACK for the last byte. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci writel(priv->len, priv->membase + UNIPHIER_FI2C_RBC); 2768c2ecf20Sopenharmony_ci priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF | 2778c2ecf20Sopenharmony_ci UNIPHIER_FI2C_INT_RB; 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci /* 2808c2ecf20Sopenharmony_ci * The byte counter can not count over 256. In this case, 2818c2ecf20Sopenharmony_ci * do not use it at all. Drain data when FIFO gets full, 2828c2ecf20Sopenharmony_ci * but treat the last portion as a special case. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci writel(0, priv->membase + UNIPHIER_FI2C_RBC); 2858c2ecf20Sopenharmony_ci priv->flags |= UNIPHIER_FI2C_MANUAL_NACK; 2868c2ecf20Sopenharmony_ci priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci uniphier_fi2c_set_irqs(priv); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* set slave address with RD bit */ 2928c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1, 2938c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_DTTX); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_RST_RST, priv->membase + UNIPHIER_FI2C_RST); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void uniphier_fi2c_prepare_operation(struct uniphier_fi2c_priv *priv) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_BRST_FOEN | UNIPHIER_FI2C_BRST_RSCL, 3048c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_BRST); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci uniphier_fi2c_reset(priv); 3108c2ecf20Sopenharmony_ci i2c_recover_bus(&priv->adap); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, 3148c2ecf20Sopenharmony_ci struct i2c_msg *msg, bool repeat, 3158c2ecf20Sopenharmony_ci bool stop) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); 3188c2ecf20Sopenharmony_ci bool is_read = msg->flags & I2C_M_RD; 3198c2ecf20Sopenharmony_ci unsigned long time_left, flags; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci priv->len = msg->len; 3228c2ecf20Sopenharmony_ci priv->buf = msg->buf; 3238c2ecf20Sopenharmony_ci priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS; 3248c2ecf20Sopenharmony_ci priv->error = 0; 3258c2ecf20Sopenharmony_ci priv->flags = 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (stop) 3288c2ecf20Sopenharmony_ci priv->flags |= UNIPHIER_FI2C_STOP; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci reinit_completion(&priv->comp); 3318c2ecf20Sopenharmony_ci uniphier_fi2c_clear_irqs(priv, U32_MAX); 3328c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST, 3338c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (is_read) 3388c2ecf20Sopenharmony_ci uniphier_fi2c_rx_init(priv, msg->addr); 3398c2ecf20Sopenharmony_ci else 3408c2ecf20Sopenharmony_ci uniphier_fi2c_tx_init(priv, msg->addr, repeat); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * For a repeated START condition, writing a slave address to the FIFO 3448c2ecf20Sopenharmony_ci * kicks the controller. So, the UNIPHIER_FI2C_CR register should be 3458c2ecf20Sopenharmony_ci * written only for a non-repeated START condition. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci if (!repeat) 3488c2ecf20Sopenharmony_ci writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA, 3498c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_CR); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3568c2ecf20Sopenharmony_ci priv->enabled_irqs = 0; 3578c2ecf20Sopenharmony_ci uniphier_fi2c_set_irqs(priv); 3588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (!time_left) { 3618c2ecf20Sopenharmony_ci dev_err(&adap->dev, "transaction timeout.\n"); 3628c2ecf20Sopenharmony_ci uniphier_fi2c_recover(priv); 3638c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) { 3678c2ecf20Sopenharmony_ci u32 status; 3688c2ecf20Sopenharmony_ci int ret; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = readl_poll_timeout(priv->membase + UNIPHIER_FI2C_SR, 3718c2ecf20Sopenharmony_ci status, 3728c2ecf20Sopenharmony_ci (status & UNIPHIER_FI2C_SR_STS) && 3738c2ecf20Sopenharmony_ci !(status & UNIPHIER_FI2C_SR_BB), 3748c2ecf20Sopenharmony_ci 1, 20); 3758c2ecf20Sopenharmony_ci if (ret) { 3768c2ecf20Sopenharmony_ci dev_err(&adap->dev, 3778c2ecf20Sopenharmony_ci "stop condition was not completed.\n"); 3788c2ecf20Sopenharmony_ci uniphier_fi2c_recover(priv); 3798c2ecf20Sopenharmony_ci return ret; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return priv->error; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (readl(priv->membase + UNIPHIER_FI2C_SR) & UNIPHIER_FI2C_SR_DB) { 3918c2ecf20Sopenharmony_ci if (priv->busy_cnt++ > 3) { 3928c2ecf20Sopenharmony_ci /* 3938c2ecf20Sopenharmony_ci * If bus busy continues too long, it is probably 3948c2ecf20Sopenharmony_ci * in a wrong state. Try bus recovery. 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci uniphier_fi2c_recover(priv); 3978c2ecf20Sopenharmony_ci priv->busy_cnt = 0; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return -EAGAIN; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci priv->busy_cnt = 0; 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, 4088c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct i2c_msg *msg, *emsg = msgs + num; 4118c2ecf20Sopenharmony_ci bool repeat = false; 4128c2ecf20Sopenharmony_ci int ret; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ret = uniphier_fi2c_check_bus_busy(adap); 4158c2ecf20Sopenharmony_ci if (ret) 4168c2ecf20Sopenharmony_ci return ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci for (msg = msgs; msg < emsg; msg++) { 4198c2ecf20Sopenharmony_ci /* Emit STOP if it is the last message or I2C_M_STOP is set. */ 4208c2ecf20Sopenharmony_ci bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop); 4238c2ecf20Sopenharmony_ci if (ret) 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci repeat = !stop; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return num; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic u32 uniphier_fi2c_functionality(struct i2c_adapter *adap) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic const struct i2c_algorithm uniphier_fi2c_algo = { 4388c2ecf20Sopenharmony_ci .master_xfer = uniphier_fi2c_master_xfer, 4398c2ecf20Sopenharmony_ci .functionality = uniphier_fi2c_functionality, 4408c2ecf20Sopenharmony_ci}; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int uniphier_fi2c_get_scl(struct i2c_adapter *adap) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return !!(readl(priv->membase + UNIPHIER_FI2C_BM) & 4478c2ecf20Sopenharmony_ci UNIPHIER_FI2C_BM_SCLS); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void uniphier_fi2c_set_scl(struct i2c_adapter *adap, int val) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci writel(val ? UNIPHIER_FI2C_BRST_RSCL : 0, 4558c2ecf20Sopenharmony_ci priv->membase + UNIPHIER_FI2C_BRST); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int uniphier_fi2c_get_sda(struct i2c_adapter *adap) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return !!(readl(priv->membase + UNIPHIER_FI2C_BM) & 4638c2ecf20Sopenharmony_ci UNIPHIER_FI2C_BM_SDAS); 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void uniphier_fi2c_unprepare_recovery(struct i2c_adapter *adap) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci uniphier_fi2c_prepare_operation(i2c_get_adapdata(adap)); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = { 4728c2ecf20Sopenharmony_ci .recover_bus = i2c_generic_scl_recovery, 4738c2ecf20Sopenharmony_ci .get_scl = uniphier_fi2c_get_scl, 4748c2ecf20Sopenharmony_ci .set_scl = uniphier_fi2c_set_scl, 4758c2ecf20Sopenharmony_ci .get_sda = uniphier_fi2c_get_sda, 4768c2ecf20Sopenharmony_ci .unprepare_recovery = uniphier_fi2c_unprepare_recovery, 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci unsigned int cyc = priv->clk_cycle; 4828c2ecf20Sopenharmony_ci u32 tmp; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci tmp = readl(priv->membase + UNIPHIER_FI2C_CR); 4858c2ecf20Sopenharmony_ci tmp |= UNIPHIER_FI2C_CR_MST; 4868c2ecf20Sopenharmony_ci writel(tmp, priv->membase + UNIPHIER_FI2C_CR); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci uniphier_fi2c_reset(priv); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * Standard-mode: tLOW + tHIGH = 10 us 4928c2ecf20Sopenharmony_ci * Fast-mode: tLOW + tHIGH = 2.5 us 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci writel(cyc, priv->membase + UNIPHIER_FI2C_CYC); 4958c2ecf20Sopenharmony_ci /* 4968c2ecf20Sopenharmony_ci * Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us, tBUF = 4.7 us 4978c2ecf20Sopenharmony_ci * Fast-mode: tLOW = 1.3 us, tHIGH = 0.6 us, tBUF = 1.3 us 4988c2ecf20Sopenharmony_ci * "tLow/tHIGH = 5/4" meets both. 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci writel(cyc * 5 / 9, priv->membase + UNIPHIER_FI2C_LCTL); 5018c2ecf20Sopenharmony_ci /* 5028c2ecf20Sopenharmony_ci * Standard-mode: tHD;STA = 4.0 us, tSU;STA = 4.7 us, tSU;STO = 4.0 us 5038c2ecf20Sopenharmony_ci * Fast-mode: tHD;STA = 0.6 us, tSU;STA = 0.6 us, tSU;STO = 0.6 us 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci writel(cyc / 2, priv->membase + UNIPHIER_FI2C_SSUT); 5068c2ecf20Sopenharmony_ci /* 5078c2ecf20Sopenharmony_ci * Standard-mode: tSU;DAT = 250 ns 5088c2ecf20Sopenharmony_ci * Fast-mode: tSU;DAT = 100 ns 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_ci writel(cyc / 16, priv->membase + UNIPHIER_FI2C_DSUT); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci uniphier_fi2c_prepare_operation(priv); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int uniphier_fi2c_probe(struct platform_device *pdev) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5188c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv; 5198c2ecf20Sopenharmony_ci u32 bus_speed; 5208c2ecf20Sopenharmony_ci unsigned long clk_rate; 5218c2ecf20Sopenharmony_ci int irq, ret; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 5248c2ecf20Sopenharmony_ci if (!priv) 5258c2ecf20Sopenharmony_ci return -ENOMEM; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci priv->membase = devm_platform_ioremap_resource(pdev, 0); 5288c2ecf20Sopenharmony_ci if (IS_ERR(priv->membase)) 5298c2ecf20Sopenharmony_ci return PTR_ERR(priv->membase); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 5328c2ecf20Sopenharmony_ci if (irq < 0) 5338c2ecf20Sopenharmony_ci return irq; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) 5368c2ecf20Sopenharmony_ci bus_speed = I2C_MAX_STANDARD_MODE_FREQ; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!bus_speed || bus_speed > I2C_MAX_FAST_MODE_FREQ) { 5398c2ecf20Sopenharmony_ci dev_err(dev, "invalid clock-frequency %d\n", bus_speed); 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(dev, NULL); 5448c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) { 5458c2ecf20Sopenharmony_ci dev_err(dev, "failed to get clock\n"); 5468c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 5508c2ecf20Sopenharmony_ci if (ret) 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci clk_rate = clk_get_rate(priv->clk); 5548c2ecf20Sopenharmony_ci if (!clk_rate) { 5558c2ecf20Sopenharmony_ci dev_err(dev, "input clock rate should not be zero\n"); 5568c2ecf20Sopenharmony_ci ret = -EINVAL; 5578c2ecf20Sopenharmony_ci goto disable_clk; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci priv->clk_cycle = clk_rate / bus_speed; 5618c2ecf20Sopenharmony_ci init_completion(&priv->comp); 5628c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 5638c2ecf20Sopenharmony_ci priv->adap.owner = THIS_MODULE; 5648c2ecf20Sopenharmony_ci priv->adap.algo = &uniphier_fi2c_algo; 5658c2ecf20Sopenharmony_ci priv->adap.dev.parent = dev; 5668c2ecf20Sopenharmony_ci priv->adap.dev.of_node = dev->of_node; 5678c2ecf20Sopenharmony_ci strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name)); 5688c2ecf20Sopenharmony_ci priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info; 5698c2ecf20Sopenharmony_ci i2c_set_adapdata(&priv->adap, priv); 5708c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci uniphier_fi2c_hw_init(priv); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, 5758c2ecf20Sopenharmony_ci pdev->name, priv); 5768c2ecf20Sopenharmony_ci if (ret) { 5778c2ecf20Sopenharmony_ci dev_err(dev, "failed to request irq %d\n", irq); 5788c2ecf20Sopenharmony_ci goto disable_clk; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&priv->adap); 5828c2ecf20Sopenharmony_cidisable_clk: 5838c2ecf20Sopenharmony_ci if (ret) 5848c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int uniphier_fi2c_remove(struct platform_device *pdev) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci i2c_del_adapter(&priv->adap); 5948c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic int __maybe_unused uniphier_fi2c_suspend(struct device *dev) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = dev_get_drvdata(dev); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int __maybe_unused uniphier_fi2c_resume(struct device *dev) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct uniphier_fi2c_priv *priv = dev_get_drvdata(dev); 6118c2ecf20Sopenharmony_ci int ret; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 6148c2ecf20Sopenharmony_ci if (ret) 6158c2ecf20Sopenharmony_ci return ret; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci uniphier_fi2c_hw_init(priv); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic const struct dev_pm_ops uniphier_fi2c_pm_ops = { 6238c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(uniphier_fi2c_suspend, uniphier_fi2c_resume) 6248c2ecf20Sopenharmony_ci}; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic const struct of_device_id uniphier_fi2c_match[] = { 6278c2ecf20Sopenharmony_ci { .compatible = "socionext,uniphier-fi2c" }, 6288c2ecf20Sopenharmony_ci { /* sentinel */ } 6298c2ecf20Sopenharmony_ci}; 6308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, uniphier_fi2c_match); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic struct platform_driver uniphier_fi2c_drv = { 6338c2ecf20Sopenharmony_ci .probe = uniphier_fi2c_probe, 6348c2ecf20Sopenharmony_ci .remove = uniphier_fi2c_remove, 6358c2ecf20Sopenharmony_ci .driver = { 6368c2ecf20Sopenharmony_ci .name = "uniphier-fi2c", 6378c2ecf20Sopenharmony_ci .of_match_table = uniphier_fi2c_match, 6388c2ecf20Sopenharmony_ci .pm = &uniphier_fi2c_pm_ops, 6398c2ecf20Sopenharmony_ci }, 6408c2ecf20Sopenharmony_ci}; 6418c2ecf20Sopenharmony_cimodule_platform_driver(uniphier_fi2c_drv); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); 6448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UniPhier FIFO-builtin I2C bus driver"); 6458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 646