xref: /openbmc/linux/drivers/spi/spi-sprd-adi.c (revision bb4bf8d2)
17e2903cbSBaolin Wang /*
27e2903cbSBaolin Wang  * Copyright (C) 2017 Spreadtrum Communications Inc.
37e2903cbSBaolin Wang  *
47e2903cbSBaolin Wang  * SPDX-License-Identifier: GPL-2.0
57e2903cbSBaolin Wang  */
67e2903cbSBaolin Wang 
7ac177501SBaolin Wang #include <linux/delay.h>
87e2903cbSBaolin Wang #include <linux/hwspinlock.h>
97e2903cbSBaolin Wang #include <linux/init.h>
107e2903cbSBaolin Wang #include <linux/io.h>
117e2903cbSBaolin Wang #include <linux/kernel.h>
127e2903cbSBaolin Wang #include <linux/module.h>
137e2903cbSBaolin Wang #include <linux/of.h>
147e2903cbSBaolin Wang #include <linux/of_device.h>
157e2903cbSBaolin Wang #include <linux/platform_device.h>
16ac177501SBaolin Wang #include <linux/reboot.h>
177e2903cbSBaolin Wang #include <linux/spi/spi.h>
187e2903cbSBaolin Wang #include <linux/sizes.h>
197e2903cbSBaolin Wang 
207e2903cbSBaolin Wang /* Registers definitions for ADI controller */
217e2903cbSBaolin Wang #define REG_ADI_CTRL0			0x4
227e2903cbSBaolin Wang #define REG_ADI_CHN_PRIL		0x8
237e2903cbSBaolin Wang #define REG_ADI_CHN_PRIH		0xc
247e2903cbSBaolin Wang #define REG_ADI_INT_EN			0x10
257e2903cbSBaolin Wang #define REG_ADI_INT_RAW			0x14
267e2903cbSBaolin Wang #define REG_ADI_INT_MASK		0x18
277e2903cbSBaolin Wang #define REG_ADI_INT_CLR			0x1c
287e2903cbSBaolin Wang #define REG_ADI_GSSI_CFG0		0x20
297e2903cbSBaolin Wang #define REG_ADI_GSSI_CFG1		0x24
307e2903cbSBaolin Wang #define REG_ADI_RD_CMD			0x28
317e2903cbSBaolin Wang #define REG_ADI_RD_DATA			0x2c
327e2903cbSBaolin Wang #define REG_ADI_ARM_FIFO_STS		0x30
337e2903cbSBaolin Wang #define REG_ADI_STS			0x34
347e2903cbSBaolin Wang #define REG_ADI_EVT_FIFO_STS		0x38
357e2903cbSBaolin Wang #define REG_ADI_ARM_CMD_STS		0x3c
367e2903cbSBaolin Wang #define REG_ADI_CHN_EN			0x40
377e2903cbSBaolin Wang #define REG_ADI_CHN_ADDR(id)		(0x44 + (id - 2) * 4)
387e2903cbSBaolin Wang #define REG_ADI_CHN_EN1			0x20c
397e2903cbSBaolin Wang 
407e2903cbSBaolin Wang /* Bits definitions for register REG_ADI_GSSI_CFG0 */
417e2903cbSBaolin Wang #define BIT_CLK_ALL_ON			BIT(30)
427e2903cbSBaolin Wang 
437e2903cbSBaolin Wang /* Bits definitions for register REG_ADI_RD_DATA */
447e2903cbSBaolin Wang #define BIT_RD_CMD_BUSY			BIT(31)
457e2903cbSBaolin Wang #define RD_ADDR_SHIFT			16
467e2903cbSBaolin Wang #define RD_VALUE_MASK			GENMASK(15, 0)
477e2903cbSBaolin Wang #define RD_ADDR_MASK			GENMASK(30, 16)
487e2903cbSBaolin Wang 
497e2903cbSBaolin Wang /* Bits definitions for register REG_ADI_ARM_FIFO_STS */
507e2903cbSBaolin Wang #define BIT_FIFO_FULL			BIT(11)
517e2903cbSBaolin Wang #define BIT_FIFO_EMPTY			BIT(10)
527e2903cbSBaolin Wang 
537e2903cbSBaolin Wang /*
547e2903cbSBaolin Wang  * ADI slave devices include RTC, ADC, regulator, charger, thermal and so on.
557e2903cbSBaolin Wang  * The slave devices address offset is always 0x8000 and size is 4K.
567e2903cbSBaolin Wang  */
577e2903cbSBaolin Wang #define ADI_SLAVE_ADDR_SIZE		SZ_4K
587e2903cbSBaolin Wang #define ADI_SLAVE_OFFSET		0x8000
597e2903cbSBaolin Wang 
607e2903cbSBaolin Wang /* Timeout (ms) for the trylock of hardware spinlocks */
617e2903cbSBaolin Wang #define ADI_HWSPINLOCK_TIMEOUT		5000
627e2903cbSBaolin Wang /*
637e2903cbSBaolin Wang  * ADI controller has 50 channels including 2 software channels
647e2903cbSBaolin Wang  * and 48 hardware channels.
657e2903cbSBaolin Wang  */
667e2903cbSBaolin Wang #define ADI_HW_CHNS			50
677e2903cbSBaolin Wang 
687e2903cbSBaolin Wang #define ADI_FIFO_DRAIN_TIMEOUT		1000
697e2903cbSBaolin Wang #define ADI_READ_TIMEOUT		2000
707e2903cbSBaolin Wang #define REG_ADDR_LOW_MASK		GENMASK(11, 0)
717e2903cbSBaolin Wang 
72ac177501SBaolin Wang /* Registers definitions for PMIC watchdog controller */
73ac177501SBaolin Wang #define REG_WDG_LOAD_LOW		0x80
74ac177501SBaolin Wang #define REG_WDG_LOAD_HIGH		0x84
75ac177501SBaolin Wang #define REG_WDG_CTRL			0x88
76ac177501SBaolin Wang #define REG_WDG_LOCK			0xa0
77ac177501SBaolin Wang 
78ac177501SBaolin Wang /* Bits definitions for register REG_WDG_CTRL */
79ac177501SBaolin Wang #define BIT_WDG_RUN			BIT(1)
801d00a67cSLingling Xu #define BIT_WDG_NEW			BIT(2)
81ac177501SBaolin Wang #define BIT_WDG_RST			BIT(3)
82ac177501SBaolin Wang 
83ac177501SBaolin Wang /* Registers definitions for PMIC */
84ac177501SBaolin Wang #define PMIC_RST_STATUS			0xee8
85ac177501SBaolin Wang #define PMIC_MODULE_EN			0xc08
86ac177501SBaolin Wang #define PMIC_CLK_EN			0xc18
87ac177501SBaolin Wang #define BIT_WDG_EN			BIT(2)
88ac177501SBaolin Wang 
89ac177501SBaolin Wang /* Definition of PMIC reset status register */
90cc6b3431SChenxu Wei #define HWRST_STATUS_SECURITY		0x02
91ac177501SBaolin Wang #define HWRST_STATUS_RECOVERY		0x20
92ac177501SBaolin Wang #define HWRST_STATUS_NORMAL		0x40
93ac177501SBaolin Wang #define HWRST_STATUS_ALARM		0x50
94ac177501SBaolin Wang #define HWRST_STATUS_SLEEP		0x60
95ac177501SBaolin Wang #define HWRST_STATUS_FASTBOOT		0x30
96ac177501SBaolin Wang #define HWRST_STATUS_SPECIAL		0x70
97ac177501SBaolin Wang #define HWRST_STATUS_PANIC		0x80
98ac177501SBaolin Wang #define HWRST_STATUS_CFTREBOOT		0x90
99ac177501SBaolin Wang #define HWRST_STATUS_AUTODLOADER	0xa0
100ac177501SBaolin Wang #define HWRST_STATUS_IQMODE		0xb0
101ac177501SBaolin Wang #define HWRST_STATUS_SPRDISK		0xc0
1029d9aa1ccSSherry Zong #define HWRST_STATUS_FACTORYTEST	0xe0
103e6d722caSSherry Zong #define HWRST_STATUS_WATCHDOG		0xf0
104ac177501SBaolin Wang 
105ac177501SBaolin Wang /* Use default timeout 50 ms that converts to watchdog values */
106ac177501SBaolin Wang #define WDG_LOAD_VAL			((50 * 1000) / 32768)
107ac177501SBaolin Wang #define WDG_LOAD_MASK			GENMASK(15, 0)
108ac177501SBaolin Wang #define WDG_UNLOCK_KEY			0xe551
109ac177501SBaolin Wang 
1107e2903cbSBaolin Wang struct sprd_adi {
1117e2903cbSBaolin Wang 	struct spi_controller	*ctlr;
1127e2903cbSBaolin Wang 	struct device		*dev;
1137e2903cbSBaolin Wang 	void __iomem		*base;
1147e2903cbSBaolin Wang 	struct hwspinlock	*hwlock;
1157e2903cbSBaolin Wang 	unsigned long		slave_vbase;
1167e2903cbSBaolin Wang 	unsigned long		slave_pbase;
117ac177501SBaolin Wang 	struct notifier_block	restart_handler;
1187e2903cbSBaolin Wang };
1197e2903cbSBaolin Wang 
1207e2903cbSBaolin Wang static int sprd_adi_check_paddr(struct sprd_adi *sadi, u32 paddr)
1217e2903cbSBaolin Wang {
1227e2903cbSBaolin Wang 	if (paddr < sadi->slave_pbase || paddr >
1237e2903cbSBaolin Wang 	    (sadi->slave_pbase + ADI_SLAVE_ADDR_SIZE)) {
1247e2903cbSBaolin Wang 		dev_err(sadi->dev,
1257e2903cbSBaolin Wang 			"slave physical address is incorrect, addr = 0x%x\n",
1267e2903cbSBaolin Wang 			paddr);
1277e2903cbSBaolin Wang 		return -EINVAL;
1287e2903cbSBaolin Wang 	}
1297e2903cbSBaolin Wang 
1307e2903cbSBaolin Wang 	return 0;
1317e2903cbSBaolin Wang }
1327e2903cbSBaolin Wang 
1337e2903cbSBaolin Wang static unsigned long sprd_adi_to_vaddr(struct sprd_adi *sadi, u32 paddr)
1347e2903cbSBaolin Wang {
1357e2903cbSBaolin Wang 	return (paddr - sadi->slave_pbase + sadi->slave_vbase);
1367e2903cbSBaolin Wang }
1377e2903cbSBaolin Wang 
1387e2903cbSBaolin Wang static int sprd_adi_drain_fifo(struct sprd_adi *sadi)
1397e2903cbSBaolin Wang {
1407e2903cbSBaolin Wang 	u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
1417e2903cbSBaolin Wang 	u32 sts;
1427e2903cbSBaolin Wang 
1437e2903cbSBaolin Wang 	do {
1447e2903cbSBaolin Wang 		sts = readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS);
1457e2903cbSBaolin Wang 		if (sts & BIT_FIFO_EMPTY)
1467e2903cbSBaolin Wang 			break;
1477e2903cbSBaolin Wang 
1487e2903cbSBaolin Wang 		cpu_relax();
1497e2903cbSBaolin Wang 	} while (--timeout);
1507e2903cbSBaolin Wang 
1517e2903cbSBaolin Wang 	if (timeout == 0) {
1527e2903cbSBaolin Wang 		dev_err(sadi->dev, "drain write fifo timeout\n");
1537e2903cbSBaolin Wang 		return -EBUSY;
1547e2903cbSBaolin Wang 	}
1557e2903cbSBaolin Wang 
1567e2903cbSBaolin Wang 	return 0;
1577e2903cbSBaolin Wang }
1587e2903cbSBaolin Wang 
1597e2903cbSBaolin Wang static int sprd_adi_fifo_is_full(struct sprd_adi *sadi)
1607e2903cbSBaolin Wang {
1617e2903cbSBaolin Wang 	return readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS) & BIT_FIFO_FULL;
1627e2903cbSBaolin Wang }
1637e2903cbSBaolin Wang 
1647e2903cbSBaolin Wang static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val)
1657e2903cbSBaolin Wang {
1667e2903cbSBaolin Wang 	int read_timeout = ADI_READ_TIMEOUT;
167a61aa683SBaolin Wang 	unsigned long flags;
1687e2903cbSBaolin Wang 	u32 val, rd_addr;
169f9adf61eSBaolin Wang 	int ret = 0;
170a61aa683SBaolin Wang 
171f9adf61eSBaolin Wang 	if (sadi->hwlock) {
172a61aa683SBaolin Wang 		ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
173a61aa683SBaolin Wang 						  ADI_HWSPINLOCK_TIMEOUT,
174a61aa683SBaolin Wang 						  &flags);
175a61aa683SBaolin Wang 		if (ret) {
176a61aa683SBaolin Wang 			dev_err(sadi->dev, "get the hw lock failed\n");
177a61aa683SBaolin Wang 			return ret;
178a61aa683SBaolin Wang 		}
179f9adf61eSBaolin Wang 	}
1807e2903cbSBaolin Wang 
1817e2903cbSBaolin Wang 	/*
1827e2903cbSBaolin Wang 	 * Set the physical register address need to read into RD_CMD register,
1837e2903cbSBaolin Wang 	 * then ADI controller will start to transfer automatically.
1847e2903cbSBaolin Wang 	 */
1857e2903cbSBaolin Wang 	writel_relaxed(reg_paddr, sadi->base + REG_ADI_RD_CMD);
1867e2903cbSBaolin Wang 
1877e2903cbSBaolin Wang 	/*
1887e2903cbSBaolin Wang 	 * Wait read operation complete, the BIT_RD_CMD_BUSY will be set
1897e2903cbSBaolin Wang 	 * simultaneously when writing read command to register, and the
1907e2903cbSBaolin Wang 	 * BIT_RD_CMD_BUSY will be cleared after the read operation is
1917e2903cbSBaolin Wang 	 * completed.
1927e2903cbSBaolin Wang 	 */
1937e2903cbSBaolin Wang 	do {
1947e2903cbSBaolin Wang 		val = readl_relaxed(sadi->base + REG_ADI_RD_DATA);
1957e2903cbSBaolin Wang 		if (!(val & BIT_RD_CMD_BUSY))
1967e2903cbSBaolin Wang 			break;
1977e2903cbSBaolin Wang 
1987e2903cbSBaolin Wang 		cpu_relax();
1997e2903cbSBaolin Wang 	} while (--read_timeout);
2007e2903cbSBaolin Wang 
2017e2903cbSBaolin Wang 	if (read_timeout == 0) {
2027e2903cbSBaolin Wang 		dev_err(sadi->dev, "ADI read timeout\n");
203a61aa683SBaolin Wang 		ret = -EBUSY;
204a61aa683SBaolin Wang 		goto out;
2057e2903cbSBaolin Wang 	}
2067e2903cbSBaolin Wang 
2077e2903cbSBaolin Wang 	/*
2087e2903cbSBaolin Wang 	 * The return value includes data and read register address, from bit 0
2097e2903cbSBaolin Wang 	 * to bit 15 are data, and from bit 16 to bit 30 are read register
2107e2903cbSBaolin Wang 	 * address. Then we can check the returned register address to validate
2117e2903cbSBaolin Wang 	 * data.
2127e2903cbSBaolin Wang 	 */
2137e2903cbSBaolin Wang 	rd_addr = (val & RD_ADDR_MASK ) >> RD_ADDR_SHIFT;
2147e2903cbSBaolin Wang 
2157e2903cbSBaolin Wang 	if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) {
2167e2903cbSBaolin Wang 		dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n",
2177e2903cbSBaolin Wang 			reg_paddr, val);
218a61aa683SBaolin Wang 		ret = -EIO;
219a61aa683SBaolin Wang 		goto out;
2207e2903cbSBaolin Wang 	}
2217e2903cbSBaolin Wang 
2227e2903cbSBaolin Wang 	*read_val = val & RD_VALUE_MASK;
223a61aa683SBaolin Wang 
224a61aa683SBaolin Wang out:
225f9adf61eSBaolin Wang 	if (sadi->hwlock)
226a61aa683SBaolin Wang 		hwspin_unlock_irqrestore(sadi->hwlock, &flags);
227a61aa683SBaolin Wang 	return ret;
2287e2903cbSBaolin Wang }
2297e2903cbSBaolin Wang 
230a61aa683SBaolin Wang static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val)
2317e2903cbSBaolin Wang {
232a61aa683SBaolin Wang 	unsigned long reg = sprd_adi_to_vaddr(sadi, reg_paddr);
2337e2903cbSBaolin Wang 	u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
234a61aa683SBaolin Wang 	unsigned long flags;
2357e2903cbSBaolin Wang 	int ret;
2367e2903cbSBaolin Wang 
237f9adf61eSBaolin Wang 	if (sadi->hwlock) {
238a61aa683SBaolin Wang 		ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
239a61aa683SBaolin Wang 						  ADI_HWSPINLOCK_TIMEOUT,
240a61aa683SBaolin Wang 						  &flags);
241a61aa683SBaolin Wang 		if (ret) {
242a61aa683SBaolin Wang 			dev_err(sadi->dev, "get the hw lock failed\n");
243a61aa683SBaolin Wang 			return ret;
244a61aa683SBaolin Wang 		}
245f9adf61eSBaolin Wang 	}
246a61aa683SBaolin Wang 
2477e2903cbSBaolin Wang 	ret = sprd_adi_drain_fifo(sadi);
2487e2903cbSBaolin Wang 	if (ret < 0)
249a61aa683SBaolin Wang 		goto out;
2507e2903cbSBaolin Wang 
2517e2903cbSBaolin Wang 	/*
2527e2903cbSBaolin Wang 	 * we should wait for write fifo is empty before writing data to PMIC
2537e2903cbSBaolin Wang 	 * registers.
2547e2903cbSBaolin Wang 	 */
2557e2903cbSBaolin Wang 	do {
2567e2903cbSBaolin Wang 		if (!sprd_adi_fifo_is_full(sadi)) {
2577e2903cbSBaolin Wang 			writel_relaxed(val, (void __iomem *)reg);
2587e2903cbSBaolin Wang 			break;
2597e2903cbSBaolin Wang 		}
2607e2903cbSBaolin Wang 
2617e2903cbSBaolin Wang 		cpu_relax();
2627e2903cbSBaolin Wang 	} while (--timeout);
2637e2903cbSBaolin Wang 
2647e2903cbSBaolin Wang 	if (timeout == 0) {
2657e2903cbSBaolin Wang 		dev_err(sadi->dev, "write fifo is full\n");
266a61aa683SBaolin Wang 		ret = -EBUSY;
2677e2903cbSBaolin Wang 	}
2687e2903cbSBaolin Wang 
269a61aa683SBaolin Wang out:
270f9adf61eSBaolin Wang 	if (sadi->hwlock)
271a61aa683SBaolin Wang 		hwspin_unlock_irqrestore(sadi->hwlock, &flags);
272a61aa683SBaolin Wang 	return ret;
2737e2903cbSBaolin Wang }
2747e2903cbSBaolin Wang 
2757e2903cbSBaolin Wang static int sprd_adi_transfer_one(struct spi_controller *ctlr,
2767e2903cbSBaolin Wang 				 struct spi_device *spi_dev,
2777e2903cbSBaolin Wang 				 struct spi_transfer *t)
2787e2903cbSBaolin Wang {
2797e2903cbSBaolin Wang 	struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
2807e2903cbSBaolin Wang 	u32 phy_reg, val;
2817e2903cbSBaolin Wang 	int ret;
2827e2903cbSBaolin Wang 
2837e2903cbSBaolin Wang 	if (t->rx_buf) {
2847e2903cbSBaolin Wang 		phy_reg = *(u32 *)t->rx_buf + sadi->slave_pbase;
2857e2903cbSBaolin Wang 
2867e2903cbSBaolin Wang 		ret = sprd_adi_check_paddr(sadi, phy_reg);
2877e2903cbSBaolin Wang 		if (ret)
2887e2903cbSBaolin Wang 			return ret;
2897e2903cbSBaolin Wang 
2907e2903cbSBaolin Wang 		ret = sprd_adi_read(sadi, phy_reg, &val);
2917e2903cbSBaolin Wang 		if (ret)
2927e2903cbSBaolin Wang 			return ret;
2937e2903cbSBaolin Wang 
2947e2903cbSBaolin Wang 		*(u32 *)t->rx_buf = val;
2957e2903cbSBaolin Wang 	} else if (t->tx_buf) {
2967e2903cbSBaolin Wang 		u32 *p = (u32 *)t->tx_buf;
2977e2903cbSBaolin Wang 
2987e2903cbSBaolin Wang 		/*
2997e2903cbSBaolin Wang 		 * Get the physical register address need to write and convert
3007e2903cbSBaolin Wang 		 * the physical address to virtual address. Since we need
3017e2903cbSBaolin Wang 		 * virtual register address to write.
3027e2903cbSBaolin Wang 		 */
3037e2903cbSBaolin Wang 		phy_reg = *p++ + sadi->slave_pbase;
3047e2903cbSBaolin Wang 		ret = sprd_adi_check_paddr(sadi, phy_reg);
3057e2903cbSBaolin Wang 		if (ret)
3067e2903cbSBaolin Wang 			return ret;
3077e2903cbSBaolin Wang 
3087e2903cbSBaolin Wang 		val = *p;
309a61aa683SBaolin Wang 		ret = sprd_adi_write(sadi, phy_reg, val);
3107e2903cbSBaolin Wang 		if (ret)
3117e2903cbSBaolin Wang 			return ret;
3127e2903cbSBaolin Wang 	} else {
3137e2903cbSBaolin Wang 		dev_err(sadi->dev, "no buffer for transfer\n");
3147e2903cbSBaolin Wang 		return -EINVAL;
3157e2903cbSBaolin Wang 	}
3167e2903cbSBaolin Wang 
3177e2903cbSBaolin Wang 	return 0;
3187e2903cbSBaolin Wang }
3197e2903cbSBaolin Wang 
320e6d722caSSherry Zong static void sprd_adi_set_wdt_rst_mode(struct sprd_adi *sadi)
321e6d722caSSherry Zong {
322bb4bf8d2SBaolin Wang #if IS_ENABLED(CONFIG_SPRD_WATCHDOG)
323e6d722caSSherry Zong 	u32 val;
324e6d722caSSherry Zong 
325e6d722caSSherry Zong 	/* Set default watchdog reboot mode */
326e6d722caSSherry Zong 	sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val);
327e6d722caSSherry Zong 	val |= HWRST_STATUS_WATCHDOG;
328e6d722caSSherry Zong 	sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val);
329e6d722caSSherry Zong #endif
330e6d722caSSherry Zong }
331e6d722caSSherry Zong 
332ac177501SBaolin Wang static int sprd_adi_restart_handler(struct notifier_block *this,
333ac177501SBaolin Wang 				    unsigned long mode, void *cmd)
334ac177501SBaolin Wang {
335ac177501SBaolin Wang 	struct sprd_adi *sadi = container_of(this, struct sprd_adi,
336ac177501SBaolin Wang 					     restart_handler);
337ac177501SBaolin Wang 	u32 val, reboot_mode = 0;
338ac177501SBaolin Wang 
339ac177501SBaolin Wang 	if (!cmd)
340ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_NORMAL;
341ac177501SBaolin Wang 	else if (!strncmp(cmd, "recovery", 8))
342ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_RECOVERY;
343ac177501SBaolin Wang 	else if (!strncmp(cmd, "alarm", 5))
344ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_ALARM;
345ac177501SBaolin Wang 	else if (!strncmp(cmd, "fastsleep", 9))
346ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_SLEEP;
347ac177501SBaolin Wang 	else if (!strncmp(cmd, "bootloader", 10))
348ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_FASTBOOT;
349ac177501SBaolin Wang 	else if (!strncmp(cmd, "panic", 5))
350ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_PANIC;
351ac177501SBaolin Wang 	else if (!strncmp(cmd, "special", 7))
352ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_SPECIAL;
353ac177501SBaolin Wang 	else if (!strncmp(cmd, "cftreboot", 9))
354ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_CFTREBOOT;
355ac177501SBaolin Wang 	else if (!strncmp(cmd, "autodloader", 11))
356ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_AUTODLOADER;
357ac177501SBaolin Wang 	else if (!strncmp(cmd, "iqmode", 6))
358ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_IQMODE;
359ac177501SBaolin Wang 	else if (!strncmp(cmd, "sprdisk", 7))
360ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_SPRDISK;
361cc6b3431SChenxu Wei 	else if (!strncmp(cmd, "tospanic", 8))
362cc6b3431SChenxu Wei 		reboot_mode = HWRST_STATUS_SECURITY;
3639d9aa1ccSSherry Zong 	else if (!strncmp(cmd, "factorytest", 11))
3649d9aa1ccSSherry Zong 		reboot_mode = HWRST_STATUS_FACTORYTEST;
365ac177501SBaolin Wang 	else
366ac177501SBaolin Wang 		reboot_mode = HWRST_STATUS_NORMAL;
367ac177501SBaolin Wang 
368ac177501SBaolin Wang 	/* Record the reboot mode */
369ac177501SBaolin Wang 	sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val);
370e6d722caSSherry Zong 	val &= ~HWRST_STATUS_WATCHDOG;
371ac177501SBaolin Wang 	val |= reboot_mode;
372ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val);
373ac177501SBaolin Wang 
374ac177501SBaolin Wang 	/* Enable the interface clock of the watchdog */
375ac177501SBaolin Wang 	sprd_adi_read(sadi, sadi->slave_pbase + PMIC_MODULE_EN, &val);
376ac177501SBaolin Wang 	val |= BIT_WDG_EN;
377ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + PMIC_MODULE_EN, val);
378ac177501SBaolin Wang 
379ac177501SBaolin Wang 	/* Enable the work clock of the watchdog */
380ac177501SBaolin Wang 	sprd_adi_read(sadi, sadi->slave_pbase + PMIC_CLK_EN, &val);
381ac177501SBaolin Wang 	val |= BIT_WDG_EN;
382ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + PMIC_CLK_EN, val);
383ac177501SBaolin Wang 
384ac177501SBaolin Wang 	/* Unlock the watchdog */
385ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY);
386ac177501SBaolin Wang 
3871d00a67cSLingling Xu 	sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val);
3881d00a67cSLingling Xu 	val |= BIT_WDG_NEW;
3891d00a67cSLingling Xu 	sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
3901d00a67cSLingling Xu 
391ac177501SBaolin Wang 	/* Load the watchdog timeout value, 50ms is always enough. */
392ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW,
393ac177501SBaolin Wang 		       WDG_LOAD_VAL & WDG_LOAD_MASK);
394ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_HIGH, 0);
395ac177501SBaolin Wang 
396ac177501SBaolin Wang 	/* Start the watchdog to reset system */
397ac177501SBaolin Wang 	sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val);
398ac177501SBaolin Wang 	val |= BIT_WDG_RUN | BIT_WDG_RST;
399ac177501SBaolin Wang 	sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
400ac177501SBaolin Wang 
40191ea1d70SLingling Xu 	/* Lock the watchdog */
40291ea1d70SLingling Xu 	sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, ~WDG_UNLOCK_KEY);
40391ea1d70SLingling Xu 
404ac177501SBaolin Wang 	mdelay(1000);
405ac177501SBaolin Wang 
406ac177501SBaolin Wang 	dev_emerg(sadi->dev, "Unable to restart system\n");
407ac177501SBaolin Wang 	return NOTIFY_DONE;
408ac177501SBaolin Wang }
409ac177501SBaolin Wang 
4107e2903cbSBaolin Wang static void sprd_adi_hw_init(struct sprd_adi *sadi)
4117e2903cbSBaolin Wang {
4127e2903cbSBaolin Wang 	struct device_node *np = sadi->dev->of_node;
4137e2903cbSBaolin Wang 	int i, size, chn_cnt;
4147e2903cbSBaolin Wang 	const __be32 *list;
4157e2903cbSBaolin Wang 	u32 tmp;
4167e2903cbSBaolin Wang 
4177e2903cbSBaolin Wang 	/* Set all channels as default priority */
4187e2903cbSBaolin Wang 	writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIL);
4197e2903cbSBaolin Wang 	writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIH);
4207e2903cbSBaolin Wang 
4217e2903cbSBaolin Wang 	/* Set clock auto gate mode */
4227e2903cbSBaolin Wang 	tmp = readl_relaxed(sadi->base + REG_ADI_GSSI_CFG0);
4237e2903cbSBaolin Wang 	tmp &= ~BIT_CLK_ALL_ON;
4247e2903cbSBaolin Wang 	writel_relaxed(tmp, sadi->base + REG_ADI_GSSI_CFG0);
4257e2903cbSBaolin Wang 
4267e2903cbSBaolin Wang 	/* Set hardware channels setting */
4277e2903cbSBaolin Wang 	list = of_get_property(np, "sprd,hw-channels", &size);
428b0d6e097SDan Carpenter 	if (!list || !size) {
4297e2903cbSBaolin Wang 		dev_info(sadi->dev, "no hw channels setting in node\n");
4307e2903cbSBaolin Wang 		return;
4317e2903cbSBaolin Wang 	}
4327e2903cbSBaolin Wang 
4337e2903cbSBaolin Wang 	chn_cnt = size / 8;
4347e2903cbSBaolin Wang 	for (i = 0; i < chn_cnt; i++) {
4357e2903cbSBaolin Wang 		u32 value;
4367e2903cbSBaolin Wang 		u32 chn_id = be32_to_cpu(*list++);
4377e2903cbSBaolin Wang 		u32 chn_config = be32_to_cpu(*list++);
4387e2903cbSBaolin Wang 
4397e2903cbSBaolin Wang 		/* Channel 0 and 1 are software channels */
4407e2903cbSBaolin Wang 		if (chn_id < 2)
4417e2903cbSBaolin Wang 			continue;
4427e2903cbSBaolin Wang 
4437e2903cbSBaolin Wang 		writel_relaxed(chn_config, sadi->base +
4447e2903cbSBaolin Wang 			       REG_ADI_CHN_ADDR(chn_id));
4457e2903cbSBaolin Wang 
44654e2fc28SBaolin Wang 		if (chn_id < 32) {
4477e2903cbSBaolin Wang 			value = readl_relaxed(sadi->base + REG_ADI_CHN_EN);
4487e2903cbSBaolin Wang 			value |= BIT(chn_id);
4497e2903cbSBaolin Wang 			writel_relaxed(value, sadi->base + REG_ADI_CHN_EN);
4507e2903cbSBaolin Wang 		} else if (chn_id < ADI_HW_CHNS) {
4517e2903cbSBaolin Wang 			value = readl_relaxed(sadi->base + REG_ADI_CHN_EN1);
4527e2903cbSBaolin Wang 			value |= BIT(chn_id - 32);
4537e2903cbSBaolin Wang 			writel_relaxed(value, sadi->base + REG_ADI_CHN_EN1);
4547e2903cbSBaolin Wang 		}
4557e2903cbSBaolin Wang 	}
4567e2903cbSBaolin Wang }
4577e2903cbSBaolin Wang 
4587e2903cbSBaolin Wang static int sprd_adi_probe(struct platform_device *pdev)
4597e2903cbSBaolin Wang {
4607e2903cbSBaolin Wang 	struct device_node *np = pdev->dev.of_node;
4617e2903cbSBaolin Wang 	struct spi_controller *ctlr;
4627e2903cbSBaolin Wang 	struct sprd_adi *sadi;
4637e2903cbSBaolin Wang 	struct resource *res;
4647e2903cbSBaolin Wang 	u32 num_chipselect;
4657e2903cbSBaolin Wang 	int ret;
4667e2903cbSBaolin Wang 
4677e2903cbSBaolin Wang 	if (!np) {
4687e2903cbSBaolin Wang 		dev_err(&pdev->dev, "can not find the adi bus node\n");
4697e2903cbSBaolin Wang 		return -ENODEV;
4707e2903cbSBaolin Wang 	}
4717e2903cbSBaolin Wang 
4727e2903cbSBaolin Wang 	pdev->id = of_alias_get_id(np, "spi");
4737e2903cbSBaolin Wang 	num_chipselect = of_get_child_count(np);
4747e2903cbSBaolin Wang 
4757e2903cbSBaolin Wang 	ctlr = spi_alloc_master(&pdev->dev, sizeof(struct sprd_adi));
4767e2903cbSBaolin Wang 	if (!ctlr)
4777e2903cbSBaolin Wang 		return -ENOMEM;
4787e2903cbSBaolin Wang 
4797e2903cbSBaolin Wang 	dev_set_drvdata(&pdev->dev, ctlr);
4807e2903cbSBaolin Wang 	sadi = spi_controller_get_devdata(ctlr);
4817e2903cbSBaolin Wang 
4827e2903cbSBaolin Wang 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4837e2903cbSBaolin Wang 	sadi->base = devm_ioremap_resource(&pdev->dev, res);
48404063a01SDan Carpenter 	if (IS_ERR(sadi->base)) {
48504063a01SDan Carpenter 		ret = PTR_ERR(sadi->base);
4867e2903cbSBaolin Wang 		goto put_ctlr;
4877e2903cbSBaolin Wang 	}
4887e2903cbSBaolin Wang 
4897e2903cbSBaolin Wang 	sadi->slave_vbase = (unsigned long)sadi->base + ADI_SLAVE_OFFSET;
4907e2903cbSBaolin Wang 	sadi->slave_pbase = res->start + ADI_SLAVE_OFFSET;
4917e2903cbSBaolin Wang 	sadi->ctlr = ctlr;
4927e2903cbSBaolin Wang 	sadi->dev = &pdev->dev;
493f9adf61eSBaolin Wang 	ret = of_hwspin_lock_get_id(np, 0);
494f9adf61eSBaolin Wang 	if (ret > 0 || (IS_ENABLED(CONFIG_HWSPINLOCK) && ret == 0)) {
495f9adf61eSBaolin Wang 		sadi->hwlock =
496f9adf61eSBaolin Wang 			devm_hwspin_lock_request_specific(&pdev->dev, ret);
4977e2903cbSBaolin Wang 		if (!sadi->hwlock) {
4987e2903cbSBaolin Wang 			ret = -ENXIO;
4997e2903cbSBaolin Wang 			goto put_ctlr;
5007e2903cbSBaolin Wang 		}
501f9adf61eSBaolin Wang 	} else {
502f9adf61eSBaolin Wang 		switch (ret) {
503f9adf61eSBaolin Wang 		case -ENOENT:
504f9adf61eSBaolin Wang 			dev_info(&pdev->dev, "no hardware spinlock supplied\n");
505f9adf61eSBaolin Wang 			break;
506f9adf61eSBaolin Wang 		default:
507f9adf61eSBaolin Wang 			dev_err(&pdev->dev,
508f9adf61eSBaolin Wang 				"failed to find hwlock id, %d\n", ret);
509f9adf61eSBaolin Wang 			/* fall-through */
510f9adf61eSBaolin Wang 		case -EPROBE_DEFER:
511f9adf61eSBaolin Wang 			goto put_ctlr;
512f9adf61eSBaolin Wang 		}
513f9adf61eSBaolin Wang 	}
5147e2903cbSBaolin Wang 
5157e2903cbSBaolin Wang 	sprd_adi_hw_init(sadi);
516e6d722caSSherry Zong 	sprd_adi_set_wdt_rst_mode(sadi);
5177e2903cbSBaolin Wang 
5187e2903cbSBaolin Wang 	ctlr->dev.of_node = pdev->dev.of_node;
5197e2903cbSBaolin Wang 	ctlr->bus_num = pdev->id;
5207e2903cbSBaolin Wang 	ctlr->num_chipselect = num_chipselect;
5217e2903cbSBaolin Wang 	ctlr->flags = SPI_MASTER_HALF_DUPLEX;
5227e2903cbSBaolin Wang 	ctlr->bits_per_word_mask = 0;
5237e2903cbSBaolin Wang 	ctlr->transfer_one = sprd_adi_transfer_one;
5247e2903cbSBaolin Wang 
5257e2903cbSBaolin Wang 	ret = devm_spi_register_controller(&pdev->dev, ctlr);
5267e2903cbSBaolin Wang 	if (ret) {
5277e2903cbSBaolin Wang 		dev_err(&pdev->dev, "failed to register SPI controller\n");
528c8d04989SBaolin Wang 		goto put_ctlr;
5297e2903cbSBaolin Wang 	}
5307e2903cbSBaolin Wang 
531ac177501SBaolin Wang 	sadi->restart_handler.notifier_call = sprd_adi_restart_handler;
532ac177501SBaolin Wang 	sadi->restart_handler.priority = 128;
533ac177501SBaolin Wang 	ret = register_restart_handler(&sadi->restart_handler);
534ac177501SBaolin Wang 	if (ret) {
535ac177501SBaolin Wang 		dev_err(&pdev->dev, "can not register restart handler\n");
536c8d04989SBaolin Wang 		goto put_ctlr;
537ac177501SBaolin Wang 	}
538ac177501SBaolin Wang 
5397e2903cbSBaolin Wang 	return 0;
5407e2903cbSBaolin Wang 
5417e2903cbSBaolin Wang put_ctlr:
5427e2903cbSBaolin Wang 	spi_controller_put(ctlr);
5437e2903cbSBaolin Wang 	return ret;
5447e2903cbSBaolin Wang }
5457e2903cbSBaolin Wang 
5467e2903cbSBaolin Wang static int sprd_adi_remove(struct platform_device *pdev)
5477e2903cbSBaolin Wang {
5487e2903cbSBaolin Wang 	struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
5497e2903cbSBaolin Wang 	struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
5507e2903cbSBaolin Wang 
551ac177501SBaolin Wang 	unregister_restart_handler(&sadi->restart_handler);
5527e2903cbSBaolin Wang 	return 0;
5537e2903cbSBaolin Wang }
5547e2903cbSBaolin Wang 
5557e2903cbSBaolin Wang static const struct of_device_id sprd_adi_of_match[] = {
5567e2903cbSBaolin Wang 	{
5577e2903cbSBaolin Wang 		.compatible = "sprd,sc9860-adi",
5587e2903cbSBaolin Wang 	},
5597e2903cbSBaolin Wang 	{ },
5607e2903cbSBaolin Wang };
5617e2903cbSBaolin Wang MODULE_DEVICE_TABLE(of, sprd_adi_of_match);
5627e2903cbSBaolin Wang 
5637e2903cbSBaolin Wang static struct platform_driver sprd_adi_driver = {
5647e2903cbSBaolin Wang 	.driver = {
5657e2903cbSBaolin Wang 		.name = "sprd-adi",
5667e2903cbSBaolin Wang 		.of_match_table = sprd_adi_of_match,
5677e2903cbSBaolin Wang 	},
5687e2903cbSBaolin Wang 	.probe = sprd_adi_probe,
5697e2903cbSBaolin Wang 	.remove = sprd_adi_remove,
5707e2903cbSBaolin Wang };
5717e2903cbSBaolin Wang module_platform_driver(sprd_adi_driver);
5727e2903cbSBaolin Wang 
5737e2903cbSBaolin Wang MODULE_DESCRIPTION("Spreadtrum ADI Controller Driver");
5747e2903cbSBaolin Wang MODULE_AUTHOR("Baolin Wang <Baolin.Wang@spreadtrum.com>");
5757e2903cbSBaolin Wang MODULE_LICENSE("GPL v2");
576