12a22f1b3STomer Maimon // SPDX-License-Identifier: GPL-2.0
22a22f1b3STomer Maimon // Copyright (c) 2018 Nuvoton Technology corporation.
32a22f1b3STomer Maimon
42a22f1b3STomer Maimon #include <linux/kernel.h>
52a22f1b3STomer Maimon #include <linux/bitfield.h>
62a22f1b3STomer Maimon #include <linux/bitops.h>
72a22f1b3STomer Maimon #include <linux/clk.h>
82a22f1b3STomer Maimon #include <linux/interrupt.h>
92a22f1b3STomer Maimon #include <linux/io.h>
102a22f1b3STomer Maimon #include <linux/module.h>
112a22f1b3STomer Maimon #include <linux/platform_device.h>
122a22f1b3STomer Maimon #include <linux/spi/spi.h>
13b5df0b2eSTomer Maimon #include <linux/reset.h>
142a22f1b3STomer Maimon
152a22f1b3STomer Maimon #include <asm/unaligned.h>
162a22f1b3STomer Maimon
172a22f1b3STomer Maimon #include <linux/regmap.h>
182a22f1b3STomer Maimon #include <linux/mfd/syscon.h>
192a22f1b3STomer Maimon
202a22f1b3STomer Maimon struct npcm_pspi {
212a22f1b3STomer Maimon struct completion xfer_done;
22b5df0b2eSTomer Maimon struct reset_control *reset;
232a22f1b3STomer Maimon struct spi_master *master;
242a22f1b3STomer Maimon unsigned int tx_bytes;
252a22f1b3STomer Maimon unsigned int rx_bytes;
262a22f1b3STomer Maimon void __iomem *base;
272a22f1b3STomer Maimon bool is_save_param;
282a22f1b3STomer Maimon u8 bits_per_word;
292a22f1b3STomer Maimon const u8 *tx_buf;
302a22f1b3STomer Maimon struct clk *clk;
312a22f1b3STomer Maimon u32 speed_hz;
322a22f1b3STomer Maimon u8 *rx_buf;
332a22f1b3STomer Maimon u16 mode;
342a22f1b3STomer Maimon u32 id;
352a22f1b3STomer Maimon };
362a22f1b3STomer Maimon
372a22f1b3STomer Maimon #define DRIVER_NAME "npcm-pspi"
382a22f1b3STomer Maimon
392a22f1b3STomer Maimon #define NPCM_PSPI_DATA 0x00
402a22f1b3STomer Maimon #define NPCM_PSPI_CTL1 0x02
412a22f1b3STomer Maimon #define NPCM_PSPI_STAT 0x04
422a22f1b3STomer Maimon
432a22f1b3STomer Maimon /* definitions for control and status register */
442a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SPIEN BIT(0)
452a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_MOD BIT(2)
462a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_EIR BIT(5)
472a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_EIW BIT(6)
482a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SCM BIT(7)
492a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SCIDL BIT(8)
502a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SCDV6_0 GENMASK(15, 9)
512a22f1b3STomer Maimon
522a22f1b3STomer Maimon #define NPCM_PSPI_STAT_BSY BIT(0)
532a22f1b3STomer Maimon #define NPCM_PSPI_STAT_RBF BIT(1)
542a22f1b3STomer Maimon
552a22f1b3STomer Maimon /* general definitions */
562a22f1b3STomer Maimon #define NPCM_PSPI_TIMEOUT_MS 2000
572a22f1b3STomer Maimon #define NPCM_PSPI_MAX_CLK_DIVIDER 256
582a22f1b3STomer Maimon #define NPCM_PSPI_MIN_CLK_DIVIDER 4
592a22f1b3STomer Maimon #define NPCM_PSPI_DEFAULT_CLK 25000000
602a22f1b3STomer Maimon
bytes_per_word(unsigned int bits)612a22f1b3STomer Maimon static inline unsigned int bytes_per_word(unsigned int bits)
622a22f1b3STomer Maimon {
632a22f1b3STomer Maimon return bits <= 8 ? 1 : 2;
642a22f1b3STomer Maimon }
652a22f1b3STomer Maimon
npcm_pspi_irq_enable(struct npcm_pspi * priv,u16 mask)662a22f1b3STomer Maimon static inline void npcm_pspi_irq_enable(struct npcm_pspi *priv, u16 mask)
672a22f1b3STomer Maimon {
682a22f1b3STomer Maimon u16 val;
692a22f1b3STomer Maimon
702a22f1b3STomer Maimon val = ioread16(priv->base + NPCM_PSPI_CTL1);
712a22f1b3STomer Maimon val |= mask;
722a22f1b3STomer Maimon iowrite16(val, priv->base + NPCM_PSPI_CTL1);
732a22f1b3STomer Maimon }
742a22f1b3STomer Maimon
npcm_pspi_irq_disable(struct npcm_pspi * priv,u16 mask)752a22f1b3STomer Maimon static inline void npcm_pspi_irq_disable(struct npcm_pspi *priv, u16 mask)
762a22f1b3STomer Maimon {
772a22f1b3STomer Maimon u16 val;
782a22f1b3STomer Maimon
792a22f1b3STomer Maimon val = ioread16(priv->base + NPCM_PSPI_CTL1);
802a22f1b3STomer Maimon val &= ~mask;
812a22f1b3STomer Maimon iowrite16(val, priv->base + NPCM_PSPI_CTL1);
822a22f1b3STomer Maimon }
832a22f1b3STomer Maimon
npcm_pspi_enable(struct npcm_pspi * priv)842a22f1b3STomer Maimon static inline void npcm_pspi_enable(struct npcm_pspi *priv)
852a22f1b3STomer Maimon {
862a22f1b3STomer Maimon u16 val;
872a22f1b3STomer Maimon
882a22f1b3STomer Maimon val = ioread16(priv->base + NPCM_PSPI_CTL1);
892a22f1b3STomer Maimon val |= NPCM_PSPI_CTL1_SPIEN;
902a22f1b3STomer Maimon iowrite16(val, priv->base + NPCM_PSPI_CTL1);
912a22f1b3STomer Maimon }
922a22f1b3STomer Maimon
npcm_pspi_disable(struct npcm_pspi * priv)932a22f1b3STomer Maimon static inline void npcm_pspi_disable(struct npcm_pspi *priv)
942a22f1b3STomer Maimon {
952a22f1b3STomer Maimon u16 val;
962a22f1b3STomer Maimon
972a22f1b3STomer Maimon val = ioread16(priv->base + NPCM_PSPI_CTL1);
982a22f1b3STomer Maimon val &= ~NPCM_PSPI_CTL1_SPIEN;
992a22f1b3STomer Maimon iowrite16(val, priv->base + NPCM_PSPI_CTL1);
1002a22f1b3STomer Maimon }
1012a22f1b3STomer Maimon
npcm_pspi_set_mode(struct spi_device * spi)1022a22f1b3STomer Maimon static void npcm_pspi_set_mode(struct spi_device *spi)
1032a22f1b3STomer Maimon {
1042a22f1b3STomer Maimon struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
1052a22f1b3STomer Maimon u16 regtemp;
1062a22f1b3STomer Maimon u16 mode_val;
1072a22f1b3STomer Maimon
10856f47edfSAndy Shevchenko switch (spi->mode & SPI_MODE_X_MASK) {
1092a22f1b3STomer Maimon case SPI_MODE_0:
1102a22f1b3STomer Maimon mode_val = 0;
1112a22f1b3STomer Maimon break;
1122a22f1b3STomer Maimon case SPI_MODE_1:
1132a22f1b3STomer Maimon mode_val = NPCM_PSPI_CTL1_SCIDL;
1142a22f1b3STomer Maimon break;
1152a22f1b3STomer Maimon case SPI_MODE_2:
1162a22f1b3STomer Maimon mode_val = NPCM_PSPI_CTL1_SCM;
1172a22f1b3STomer Maimon break;
1182a22f1b3STomer Maimon case SPI_MODE_3:
1192a22f1b3STomer Maimon mode_val = NPCM_PSPI_CTL1_SCIDL | NPCM_PSPI_CTL1_SCM;
1202a22f1b3STomer Maimon break;
1212a22f1b3STomer Maimon }
1222a22f1b3STomer Maimon
1232a22f1b3STomer Maimon regtemp = ioread16(priv->base + NPCM_PSPI_CTL1);
1242a22f1b3STomer Maimon regtemp &= ~(NPCM_PSPI_CTL1_SCM | NPCM_PSPI_CTL1_SCIDL);
1252a22f1b3STomer Maimon iowrite16(regtemp | mode_val, priv->base + NPCM_PSPI_CTL1);
1262a22f1b3STomer Maimon }
1272a22f1b3STomer Maimon
npcm_pspi_set_transfer_size(struct npcm_pspi * priv,int size)1282a22f1b3STomer Maimon static void npcm_pspi_set_transfer_size(struct npcm_pspi *priv, int size)
1292a22f1b3STomer Maimon {
1302a22f1b3STomer Maimon u16 regtemp;
1312a22f1b3STomer Maimon
1322a22f1b3STomer Maimon regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
1332a22f1b3STomer Maimon
1342a22f1b3STomer Maimon switch (size) {
1352a22f1b3STomer Maimon case 8:
1362a22f1b3STomer Maimon regtemp &= ~NPCM_PSPI_CTL1_MOD;
1372a22f1b3STomer Maimon break;
1382a22f1b3STomer Maimon case 16:
1392a22f1b3STomer Maimon regtemp |= NPCM_PSPI_CTL1_MOD;
1402a22f1b3STomer Maimon break;
1412a22f1b3STomer Maimon }
1422a22f1b3STomer Maimon
1432a22f1b3STomer Maimon iowrite16(regtemp, NPCM_PSPI_CTL1 + priv->base);
1442a22f1b3STomer Maimon }
1452a22f1b3STomer Maimon
npcm_pspi_set_baudrate(struct npcm_pspi * priv,unsigned int speed)1462a22f1b3STomer Maimon static void npcm_pspi_set_baudrate(struct npcm_pspi *priv, unsigned int speed)
1472a22f1b3STomer Maimon {
1482a22f1b3STomer Maimon u32 ckdiv;
1492a22f1b3STomer Maimon u16 regtemp;
1502a22f1b3STomer Maimon
1512a22f1b3STomer Maimon /* the supported rates are numbers from 4 to 256. */
1522a22f1b3STomer Maimon ckdiv = DIV_ROUND_CLOSEST(clk_get_rate(priv->clk), (2 * speed)) - 1;
1532a22f1b3STomer Maimon
1542a22f1b3STomer Maimon regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
1552a22f1b3STomer Maimon regtemp &= ~NPCM_PSPI_CTL1_SCDV6_0;
1562a22f1b3STomer Maimon iowrite16(regtemp | (ckdiv << 9), NPCM_PSPI_CTL1 + priv->base);
1572a22f1b3STomer Maimon }
1582a22f1b3STomer Maimon
npcm_pspi_setup_transfer(struct spi_device * spi,struct spi_transfer * t)1592a22f1b3STomer Maimon static void npcm_pspi_setup_transfer(struct spi_device *spi,
1602a22f1b3STomer Maimon struct spi_transfer *t)
1612a22f1b3STomer Maimon {
1622a22f1b3STomer Maimon struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
1632a22f1b3STomer Maimon
1642a22f1b3STomer Maimon priv->tx_buf = t->tx_buf;
1652a22f1b3STomer Maimon priv->rx_buf = t->rx_buf;
1662a22f1b3STomer Maimon priv->tx_bytes = t->len;
1672a22f1b3STomer Maimon priv->rx_bytes = t->len;
1682a22f1b3STomer Maimon
1692a22f1b3STomer Maimon if (!priv->is_save_param || priv->mode != spi->mode) {
1702a22f1b3STomer Maimon npcm_pspi_set_mode(spi);
1712a22f1b3STomer Maimon priv->mode = spi->mode;
1722a22f1b3STomer Maimon }
1732a22f1b3STomer Maimon
174b4adf5b2STomer Maimon /*
175b4adf5b2STomer Maimon * If transfer is even length, and 8 bits per word transfer,
176b4adf5b2STomer Maimon * then implement 16 bits-per-word transfer.
177b4adf5b2STomer Maimon */
178b4adf5b2STomer Maimon if (priv->bits_per_word == 8 && !(t->len & 0x1))
179b4adf5b2STomer Maimon t->bits_per_word = 16;
180b4adf5b2STomer Maimon
1812a22f1b3STomer Maimon if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
1822a22f1b3STomer Maimon npcm_pspi_set_transfer_size(priv, t->bits_per_word);
1832a22f1b3STomer Maimon priv->bits_per_word = t->bits_per_word;
1842a22f1b3STomer Maimon }
1852a22f1b3STomer Maimon
1862a22f1b3STomer Maimon if (!priv->is_save_param || priv->speed_hz != t->speed_hz) {
1872a22f1b3STomer Maimon npcm_pspi_set_baudrate(priv, t->speed_hz);
1882a22f1b3STomer Maimon priv->speed_hz = t->speed_hz;
1892a22f1b3STomer Maimon }
1902a22f1b3STomer Maimon
1912a22f1b3STomer Maimon if (!priv->is_save_param)
1922a22f1b3STomer Maimon priv->is_save_param = true;
1932a22f1b3STomer Maimon }
1942a22f1b3STomer Maimon
npcm_pspi_send(struct npcm_pspi * priv)1952a22f1b3STomer Maimon static void npcm_pspi_send(struct npcm_pspi *priv)
1962a22f1b3STomer Maimon {
1972a22f1b3STomer Maimon int wsize;
19847416a5fSTomer Maimon u16 val;
1992a22f1b3STomer Maimon
2002a22f1b3STomer Maimon wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes);
2012a22f1b3STomer Maimon priv->tx_bytes -= wsize;
2022a22f1b3STomer Maimon
2031fa33be3STomer Maimon if (!priv->tx_buf)
2041fa33be3STomer Maimon return;
2051fa33be3STomer Maimon
2061fa33be3STomer Maimon switch (wsize) {
2071fa33be3STomer Maimon case 1:
20847416a5fSTomer Maimon val = *priv->tx_buf++;
20947416a5fSTomer Maimon iowrite8(val, NPCM_PSPI_DATA + priv->base);
2101fa33be3STomer Maimon break;
2111fa33be3STomer Maimon case 2:
21247416a5fSTomer Maimon val = *priv->tx_buf++;
21347416a5fSTomer Maimon val = *priv->tx_buf++ | (val << 8);
21447416a5fSTomer Maimon iowrite16(val, NPCM_PSPI_DATA + priv->base);
2151fa33be3STomer Maimon break;
2161fa33be3STomer Maimon default:
2171fa33be3STomer Maimon WARN_ON_ONCE(1);
2181fa33be3STomer Maimon return;
2191fa33be3STomer Maimon }
2202a22f1b3STomer Maimon }
2212a22f1b3STomer Maimon
npcm_pspi_recv(struct npcm_pspi * priv)2222a22f1b3STomer Maimon static void npcm_pspi_recv(struct npcm_pspi *priv)
2232a22f1b3STomer Maimon {
2242a22f1b3STomer Maimon int rsize;
2252a22f1b3STomer Maimon u16 val;
2262a22f1b3STomer Maimon
2272a22f1b3STomer Maimon rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes);
2282a22f1b3STomer Maimon priv->rx_bytes -= rsize;
2292a22f1b3STomer Maimon
2301d2319efSOlof Johansson if (!priv->rx_buf)
2311d2319efSOlof Johansson return;
2321d2319efSOlof Johansson
2331d2319efSOlof Johansson switch (rsize) {
2341d2319efSOlof Johansson case 1:
23547416a5fSTomer Maimon *priv->rx_buf++ = ioread8(priv->base + NPCM_PSPI_DATA);
2361d2319efSOlof Johansson break;
2371d2319efSOlof Johansson case 2:
2382a22f1b3STomer Maimon val = ioread16(priv->base + NPCM_PSPI_DATA);
23947416a5fSTomer Maimon *priv->rx_buf++ = (val >> 8);
24047416a5fSTomer Maimon *priv->rx_buf++ = val & 0xff;
2411d2319efSOlof Johansson break;
2421d2319efSOlof Johansson default:
2431d2319efSOlof Johansson WARN_ON_ONCE(1);
2441d2319efSOlof Johansson return;
2451d2319efSOlof Johansson }
2462a22f1b3STomer Maimon }
2472a22f1b3STomer Maimon
npcm_pspi_transfer_one(struct spi_master * master,struct spi_device * spi,struct spi_transfer * t)2482a22f1b3STomer Maimon static int npcm_pspi_transfer_one(struct spi_master *master,
2492a22f1b3STomer Maimon struct spi_device *spi,
2502a22f1b3STomer Maimon struct spi_transfer *t)
2512a22f1b3STomer Maimon {
2522a22f1b3STomer Maimon struct npcm_pspi *priv = spi_master_get_devdata(master);
2532a22f1b3STomer Maimon int status;
2542a22f1b3STomer Maimon
2552a22f1b3STomer Maimon npcm_pspi_setup_transfer(spi, t);
2562a22f1b3STomer Maimon reinit_completion(&priv->xfer_done);
2572a22f1b3STomer Maimon npcm_pspi_enable(priv);
2582a22f1b3STomer Maimon status = wait_for_completion_timeout(&priv->xfer_done,
2592a22f1b3STomer Maimon msecs_to_jiffies
2602a22f1b3STomer Maimon (NPCM_PSPI_TIMEOUT_MS));
2612a22f1b3STomer Maimon if (status == 0) {
2622a22f1b3STomer Maimon npcm_pspi_disable(priv);
2632a22f1b3STomer Maimon return -ETIMEDOUT;
2642a22f1b3STomer Maimon }
2652a22f1b3STomer Maimon
2662a22f1b3STomer Maimon return 0;
2672a22f1b3STomer Maimon }
2682a22f1b3STomer Maimon
npcm_pspi_prepare_transfer_hardware(struct spi_master * master)2692a22f1b3STomer Maimon static int npcm_pspi_prepare_transfer_hardware(struct spi_master *master)
2702a22f1b3STomer Maimon {
2712a22f1b3STomer Maimon struct npcm_pspi *priv = spi_master_get_devdata(master);
2722a22f1b3STomer Maimon
2732a22f1b3STomer Maimon npcm_pspi_irq_enable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
2742a22f1b3STomer Maimon
2752a22f1b3STomer Maimon return 0;
2762a22f1b3STomer Maimon }
2772a22f1b3STomer Maimon
npcm_pspi_unprepare_transfer_hardware(struct spi_master * master)2782a22f1b3STomer Maimon static int npcm_pspi_unprepare_transfer_hardware(struct spi_master *master)
2792a22f1b3STomer Maimon {
2802a22f1b3STomer Maimon struct npcm_pspi *priv = spi_master_get_devdata(master);
2812a22f1b3STomer Maimon
2822a22f1b3STomer Maimon npcm_pspi_irq_disable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
2832a22f1b3STomer Maimon
2842a22f1b3STomer Maimon return 0;
2852a22f1b3STomer Maimon }
2862a22f1b3STomer Maimon
npcm_pspi_reset_hw(struct npcm_pspi * priv)2872a22f1b3STomer Maimon static void npcm_pspi_reset_hw(struct npcm_pspi *priv)
2882a22f1b3STomer Maimon {
289b5df0b2eSTomer Maimon reset_control_assert(priv->reset);
290b5df0b2eSTomer Maimon udelay(5);
291b5df0b2eSTomer Maimon reset_control_deassert(priv->reset);
2922a22f1b3STomer Maimon }
2932a22f1b3STomer Maimon
npcm_pspi_handler(int irq,void * dev_id)2942a22f1b3STomer Maimon static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
2952a22f1b3STomer Maimon {
2962a22f1b3STomer Maimon struct npcm_pspi *priv = dev_id;
2972a22f1b3STomer Maimon u8 stat;
2982a22f1b3STomer Maimon
2992a22f1b3STomer Maimon stat = ioread8(priv->base + NPCM_PSPI_STAT);
3002a22f1b3STomer Maimon
3012a22f1b3STomer Maimon if (!priv->tx_buf && !priv->rx_buf)
3022a22f1b3STomer Maimon return IRQ_NONE;
3032a22f1b3STomer Maimon
3042a22f1b3STomer Maimon if (priv->tx_buf) {
3052a22f1b3STomer Maimon if (stat & NPCM_PSPI_STAT_RBF) {
306c46652eeSzhengbin ioread8(NPCM_PSPI_DATA + priv->base);
3072a22f1b3STomer Maimon if (priv->tx_bytes == 0) {
3082a22f1b3STomer Maimon npcm_pspi_disable(priv);
3092a22f1b3STomer Maimon complete(&priv->xfer_done);
3102a22f1b3STomer Maimon return IRQ_HANDLED;
3112a22f1b3STomer Maimon }
3122a22f1b3STomer Maimon }
3132a22f1b3STomer Maimon
3142a22f1b3STomer Maimon if ((stat & NPCM_PSPI_STAT_BSY) == 0)
3152a22f1b3STomer Maimon if (priv->tx_bytes)
3162a22f1b3STomer Maimon npcm_pspi_send(priv);
3172a22f1b3STomer Maimon }
3182a22f1b3STomer Maimon
3192a22f1b3STomer Maimon if (priv->rx_buf) {
3202a22f1b3STomer Maimon if (stat & NPCM_PSPI_STAT_RBF) {
3212a22f1b3STomer Maimon if (!priv->rx_bytes)
3222a22f1b3STomer Maimon return IRQ_NONE;
3232a22f1b3STomer Maimon
3242a22f1b3STomer Maimon npcm_pspi_recv(priv);
3252a22f1b3STomer Maimon
3262a22f1b3STomer Maimon if (!priv->rx_bytes) {
3272a22f1b3STomer Maimon npcm_pspi_disable(priv);
3282a22f1b3STomer Maimon complete(&priv->xfer_done);
3292a22f1b3STomer Maimon return IRQ_HANDLED;
3302a22f1b3STomer Maimon }
3312a22f1b3STomer Maimon }
3322a22f1b3STomer Maimon
3332a22f1b3STomer Maimon if (((stat & NPCM_PSPI_STAT_BSY) == 0) && !priv->tx_buf)
3342a22f1b3STomer Maimon iowrite8(0x0, NPCM_PSPI_DATA + priv->base);
3352a22f1b3STomer Maimon }
3362a22f1b3STomer Maimon
3372a22f1b3STomer Maimon return IRQ_HANDLED;
3382a22f1b3STomer Maimon }
3392a22f1b3STomer Maimon
npcm_pspi_probe(struct platform_device * pdev)3402a22f1b3STomer Maimon static int npcm_pspi_probe(struct platform_device *pdev)
3412a22f1b3STomer Maimon {
3422a22f1b3STomer Maimon struct npcm_pspi *priv;
3432a22f1b3STomer Maimon struct spi_master *master;
3442a22f1b3STomer Maimon unsigned long clk_hz;
3452a22f1b3STomer Maimon int irq;
3462a22f1b3STomer Maimon int ret;
3472a22f1b3STomer Maimon
3482a22f1b3STomer Maimon master = spi_alloc_master(&pdev->dev, sizeof(*priv));
3492a22f1b3STomer Maimon if (!master)
3502a22f1b3STomer Maimon return -ENOMEM;
3512a22f1b3STomer Maimon
3522a22f1b3STomer Maimon platform_set_drvdata(pdev, master);
3532a22f1b3STomer Maimon
3542a22f1b3STomer Maimon priv = spi_master_get_devdata(master);
3552a22f1b3STomer Maimon priv->master = master;
3562a22f1b3STomer Maimon priv->is_save_param = false;
3572a22f1b3STomer Maimon
358dcbceb6dSYueHaibing priv->base = devm_platform_ioremap_resource(pdev, 0);
3592a22f1b3STomer Maimon if (IS_ERR(priv->base)) {
3602a22f1b3STomer Maimon ret = PTR_ERR(priv->base);
3612a22f1b3STomer Maimon goto out_master_put;
3622a22f1b3STomer Maimon }
3632a22f1b3STomer Maimon
3642a22f1b3STomer Maimon priv->clk = devm_clk_get(&pdev->dev, NULL);
3652a22f1b3STomer Maimon if (IS_ERR(priv->clk)) {
3662a22f1b3STomer Maimon dev_err(&pdev->dev, "failed to get clock\n");
3672a22f1b3STomer Maimon ret = PTR_ERR(priv->clk);
3682a22f1b3STomer Maimon goto out_master_put;
3692a22f1b3STomer Maimon }
3702a22f1b3STomer Maimon
3712a22f1b3STomer Maimon ret = clk_prepare_enable(priv->clk);
3722a22f1b3STomer Maimon if (ret)
3732a22f1b3STomer Maimon goto out_master_put;
3742a22f1b3STomer Maimon
3752a22f1b3STomer Maimon irq = platform_get_irq(pdev, 0);
3762a22f1b3STomer Maimon if (irq < 0) {
3772a22f1b3STomer Maimon ret = irq;
3782a22f1b3STomer Maimon goto out_disable_clk;
3792a22f1b3STomer Maimon }
3802a22f1b3STomer Maimon
381b5df0b2eSTomer Maimon priv->reset = devm_reset_control_get(&pdev->dev, NULL);
382b5df0b2eSTomer Maimon if (IS_ERR(priv->reset)) {
383b5df0b2eSTomer Maimon ret = PTR_ERR(priv->reset);
384b5df0b2eSTomer Maimon goto out_disable_clk;
3852a22f1b3STomer Maimon }
3862a22f1b3STomer Maimon
3872a22f1b3STomer Maimon /* reset SPI-HW block */
3882a22f1b3STomer Maimon npcm_pspi_reset_hw(priv);
3892a22f1b3STomer Maimon
3902a22f1b3STomer Maimon ret = devm_request_irq(&pdev->dev, irq, npcm_pspi_handler, 0,
3912a22f1b3STomer Maimon "npcm-pspi", priv);
3922a22f1b3STomer Maimon if (ret) {
3932a22f1b3STomer Maimon dev_err(&pdev->dev, "failed to request IRQ\n");
3942a22f1b3STomer Maimon goto out_disable_clk;
3952a22f1b3STomer Maimon }
3962a22f1b3STomer Maimon
3972a22f1b3STomer Maimon init_completion(&priv->xfer_done);
3982a22f1b3STomer Maimon
3992a22f1b3STomer Maimon clk_hz = clk_get_rate(priv->clk);
4002a22f1b3STomer Maimon
4012a22f1b3STomer Maimon master->max_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MIN_CLK_DIVIDER);
4022a22f1b3STomer Maimon master->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER);
4032a22f1b3STomer Maimon master->mode_bits = SPI_CPHA | SPI_CPOL;
4042a22f1b3STomer Maimon master->dev.of_node = pdev->dev.of_node;
405b5df0b2eSTomer Maimon master->bus_num = -1;
4062a22f1b3STomer Maimon master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
4072a22f1b3STomer Maimon master->transfer_one = npcm_pspi_transfer_one;
4082a22f1b3STomer Maimon master->prepare_transfer_hardware =
4092a22f1b3STomer Maimon npcm_pspi_prepare_transfer_hardware;
4102a22f1b3STomer Maimon master->unprepare_transfer_hardware =
4112a22f1b3STomer Maimon npcm_pspi_unprepare_transfer_hardware;
412a2f234fcSLinus Walleij master->use_gpio_descriptors = true;
4132a22f1b3STomer Maimon
4142a22f1b3STomer Maimon /* set to default clock rate */
4152a22f1b3STomer Maimon npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK);
4162a22f1b3STomer Maimon
4172a22f1b3STomer Maimon ret = devm_spi_register_master(&pdev->dev, master);
4182a22f1b3STomer Maimon if (ret)
4192a22f1b3STomer Maimon goto out_disable_clk;
4202a22f1b3STomer Maimon
421b5df0b2eSTomer Maimon pr_info("NPCM Peripheral SPI %d probed\n", master->bus_num);
4222a22f1b3STomer Maimon
4232a22f1b3STomer Maimon return 0;
4242a22f1b3STomer Maimon
4252a22f1b3STomer Maimon out_disable_clk:
4262a22f1b3STomer Maimon clk_disable_unprepare(priv->clk);
4272a22f1b3STomer Maimon
4282a22f1b3STomer Maimon out_master_put:
4292a22f1b3STomer Maimon spi_master_put(master);
4302a22f1b3STomer Maimon return ret;
4312a22f1b3STomer Maimon }
4322a22f1b3STomer Maimon
npcm_pspi_remove(struct platform_device * pdev)433*445534b5SUwe Kleine-König static void npcm_pspi_remove(struct platform_device *pdev)
4342a22f1b3STomer Maimon {
43508253144SAxel Lin struct spi_master *master = platform_get_drvdata(pdev);
43608253144SAxel Lin struct npcm_pspi *priv = spi_master_get_devdata(master);
4372a22f1b3STomer Maimon
4382a22f1b3STomer Maimon npcm_pspi_reset_hw(priv);
4392a22f1b3STomer Maimon clk_disable_unprepare(priv->clk);
4402a22f1b3STomer Maimon }
4412a22f1b3STomer Maimon
4422a22f1b3STomer Maimon static const struct of_device_id npcm_pspi_match[] = {
4432a22f1b3STomer Maimon { .compatible = "nuvoton,npcm750-pspi", .data = NULL },
4446db8595aSTomer Maimon { .compatible = "nuvoton,npcm845-pspi", .data = NULL },
4452a22f1b3STomer Maimon {}
4462a22f1b3STomer Maimon };
4472a22f1b3STomer Maimon MODULE_DEVICE_TABLE(of, npcm_pspi_match);
4482a22f1b3STomer Maimon
4492a22f1b3STomer Maimon static struct platform_driver npcm_pspi_driver = {
4502a22f1b3STomer Maimon .driver = {
4512a22f1b3STomer Maimon .name = DRIVER_NAME,
4522a22f1b3STomer Maimon .of_match_table = npcm_pspi_match,
4532a22f1b3STomer Maimon },
4542a22f1b3STomer Maimon .probe = npcm_pspi_probe,
455*445534b5SUwe Kleine-König .remove_new = npcm_pspi_remove,
4562a22f1b3STomer Maimon };
4572a22f1b3STomer Maimon module_platform_driver(npcm_pspi_driver);
4582a22f1b3STomer Maimon
4592a22f1b3STomer Maimon MODULE_DESCRIPTION("NPCM peripheral SPI Controller driver");
4602a22f1b3STomer Maimon MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
4612a22f1b3STomer Maimon MODULE_LICENSE("GPL v2");
4622a22f1b3STomer Maimon
463