17813887eSMarc Kleine-Budde // SPDX-License-Identifier: GPL-2.0
27813887eSMarc Kleine-Budde // SPI to CAN driver for the Texas Instruments TCAN4x5x
37813887eSMarc Kleine-Budde // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
47813887eSMarc Kleine-Budde 
567def4efSMarc Kleine-Budde #include "tcan4x5x.h"
67813887eSMarc Kleine-Budde 
77813887eSMarc Kleine-Budde #define TCAN4X5X_EXT_CLK_DEF 40000000
87813887eSMarc Kleine-Budde 
90d6f3b25SMarkus Schneider-Pargmann #define TCAN4X5X_DEV_ID1 0x00
10142c6dc6SMarkus Schneider-Pargmann #define TCAN4X5X_DEV_ID1_TCAN 0x4e414354 /* ASCII TCAN */
110d6f3b25SMarkus Schneider-Pargmann #define TCAN4X5X_DEV_ID2 0x04
127813887eSMarc Kleine-Budde #define TCAN4X5X_REV 0x08
137813887eSMarc Kleine-Budde #define TCAN4X5X_STATUS 0x0C
1467727a17SMarkus Schneider-Pargmann #define TCAN4X5X_ERROR_STATUS_MASK 0x10
157813887eSMarc Kleine-Budde #define TCAN4X5X_CONTROL 0x14
167813887eSMarc Kleine-Budde 
177813887eSMarc Kleine-Budde #define TCAN4X5X_CONFIG 0x800
187813887eSMarc Kleine-Budde #define TCAN4X5X_TS_PRESCALE 0x804
197813887eSMarc Kleine-Budde #define TCAN4X5X_TEST_REG 0x808
207813887eSMarc Kleine-Budde #define TCAN4X5X_INT_FLAGS 0x820
217813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_INT_REG 0x824
227813887eSMarc Kleine-Budde #define TCAN4X5X_INT_EN 0x830
237813887eSMarc Kleine-Budde 
247813887eSMarc Kleine-Budde /* Interrupt bits */
257813887eSMarc Kleine-Budde #define TCAN4X5X_CANBUSTERMOPEN_INT_EN BIT(30)
267813887eSMarc Kleine-Budde #define TCAN4X5X_CANHCANL_INT_EN BIT(29)
277813887eSMarc Kleine-Budde #define TCAN4X5X_CANHBAT_INT_EN BIT(28)
287813887eSMarc Kleine-Budde #define TCAN4X5X_CANLGND_INT_EN BIT(27)
297813887eSMarc Kleine-Budde #define TCAN4X5X_CANBUSOPEN_INT_EN BIT(26)
307813887eSMarc Kleine-Budde #define TCAN4X5X_CANBUSGND_INT_EN BIT(25)
317813887eSMarc Kleine-Budde #define TCAN4X5X_CANBUSBAT_INT_EN BIT(24)
327813887eSMarc Kleine-Budde #define TCAN4X5X_UVSUP_INT_EN BIT(22)
337813887eSMarc Kleine-Budde #define TCAN4X5X_UVIO_INT_EN BIT(21)
347813887eSMarc Kleine-Budde #define TCAN4X5X_TSD_INT_EN BIT(19)
357813887eSMarc Kleine-Budde #define TCAN4X5X_ECCERR_INT_EN BIT(16)
367813887eSMarc Kleine-Budde #define TCAN4X5X_CANINT_INT_EN BIT(15)
377813887eSMarc Kleine-Budde #define TCAN4X5X_LWU_INT_EN BIT(14)
387813887eSMarc Kleine-Budde #define TCAN4X5X_CANSLNT_INT_EN BIT(10)
397813887eSMarc Kleine-Budde #define TCAN4X5X_CANDOM_INT_EN BIT(8)
407813887eSMarc Kleine-Budde #define TCAN4X5X_CANBUS_ERR_INT_EN BIT(5)
417813887eSMarc Kleine-Budde #define TCAN4X5X_BUS_FAULT BIT(4)
427813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_INT BIT(1)
437813887eSMarc Kleine-Budde #define TCAN4X5X_ENABLE_TCAN_INT \
447813887eSMarc Kleine-Budde 	(TCAN4X5X_MCAN_INT | TCAN4X5X_BUS_FAULT | \
457813887eSMarc Kleine-Budde 	 TCAN4X5X_CANBUS_ERR_INT_EN | TCAN4X5X_CANINT_INT_EN)
467813887eSMarc Kleine-Budde 
477813887eSMarc Kleine-Budde /* MCAN Interrupt bits */
487813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_ARA BIT(29)
497813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_PED BIT(28)
507813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_PEA BIT(27)
517813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_WD BIT(26)
527813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_BO BIT(25)
537813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_EW BIT(24)
547813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_EP BIT(23)
557813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_ELO BIT(22)
567813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_BEU BIT(21)
577813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_BEC BIT(20)
587813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_DRX BIT(19)
597813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TOO BIT(18)
607813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_MRAF BIT(17)
617813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TSW BIT(16)
627813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TEFL BIT(15)
637813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TEFF BIT(14)
647813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TEFW BIT(13)
657813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TEFN BIT(12)
667813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TFE BIT(11)
677813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TCF BIT(10)
687813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_TC BIT(9)
697813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_HPM BIT(8)
707813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF1L BIT(7)
717813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF1F BIT(6)
727813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF1W BIT(5)
737813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF1N BIT(4)
747813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF0L BIT(3)
757813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF0F BIT(2)
767813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF0W BIT(1)
777813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_IR_RF0N BIT(0)
787813887eSMarc Kleine-Budde #define TCAN4X5X_ENABLE_MCAN_INT \
797813887eSMarc Kleine-Budde 	(TCAN4X5X_MCAN_IR_TC | TCAN4X5X_MCAN_IR_RF0N | \
807813887eSMarc Kleine-Budde 	 TCAN4X5X_MCAN_IR_RF1N | TCAN4X5X_MCAN_IR_RF0F | \
817813887eSMarc Kleine-Budde 	 TCAN4X5X_MCAN_IR_RF1F)
827813887eSMarc Kleine-Budde 
837813887eSMarc Kleine-Budde #define TCAN4X5X_MRAM_START 0x8000
84c1b17ea7SMarkus Schneider-Pargmann #define TCAN4X5X_MRAM_SIZE 0x800
857813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_OFFSET 0x1000
867813887eSMarc Kleine-Budde 
877813887eSMarc Kleine-Budde #define TCAN4X5X_CLEAR_ALL_INT 0xffffffff
887813887eSMarc Kleine-Budde #define TCAN4X5X_SET_ALL_INT 0xffffffff
897813887eSMarc Kleine-Budde 
907813887eSMarc Kleine-Budde #define TCAN4X5X_MODE_SEL_MASK (BIT(7) | BIT(6))
917813887eSMarc Kleine-Budde #define TCAN4X5X_MODE_SLEEP 0x00
927813887eSMarc Kleine-Budde #define TCAN4X5X_MODE_STANDBY BIT(6)
937813887eSMarc Kleine-Budde #define TCAN4X5X_MODE_NORMAL BIT(7)
947813887eSMarc Kleine-Budde 
957813887eSMarc Kleine-Budde #define TCAN4X5X_DISABLE_WAKE_MSK	(BIT(31) | BIT(30))
967813887eSMarc Kleine-Budde #define TCAN4X5X_DISABLE_INH_MSK	BIT(9)
977813887eSMarc Kleine-Budde 
987813887eSMarc Kleine-Budde #define TCAN4X5X_SW_RESET BIT(2)
997813887eSMarc Kleine-Budde 
1007813887eSMarc Kleine-Budde #define TCAN4X5X_MCAN_CONFIGURED BIT(5)
1017813887eSMarc Kleine-Budde #define TCAN4X5X_WATCHDOG_EN BIT(3)
1027813887eSMarc Kleine-Budde #define TCAN4X5X_WD_60_MS_TIMER 0
1037813887eSMarc Kleine-Budde #define TCAN4X5X_WD_600_MS_TIMER BIT(28)
1047813887eSMarc Kleine-Budde #define TCAN4X5X_WD_3_S_TIMER BIT(29)
1057813887eSMarc Kleine-Budde #define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29))
1067813887eSMarc Kleine-Budde 
107142c6dc6SMarkus Schneider-Pargmann struct tcan4x5x_version_info {
108142c6dc6SMarkus Schneider-Pargmann 	const char *name;
109142c6dc6SMarkus Schneider-Pargmann 	u32 id2_register;
110142c6dc6SMarkus Schneider-Pargmann 
111142c6dc6SMarkus Schneider-Pargmann 	bool has_wake_pin;
112142c6dc6SMarkus Schneider-Pargmann 	bool has_state_pin;
113142c6dc6SMarkus Schneider-Pargmann };
114142c6dc6SMarkus Schneider-Pargmann 
115142c6dc6SMarkus Schneider-Pargmann enum {
116142c6dc6SMarkus Schneider-Pargmann 	TCAN4552 = 0,
117142c6dc6SMarkus Schneider-Pargmann 	TCAN4553,
118142c6dc6SMarkus Schneider-Pargmann 	TCAN4X5X,
119142c6dc6SMarkus Schneider-Pargmann };
120142c6dc6SMarkus Schneider-Pargmann 
121142c6dc6SMarkus Schneider-Pargmann static const struct tcan4x5x_version_info tcan4x5x_versions[] = {
122142c6dc6SMarkus Schneider-Pargmann 	[TCAN4552] = {
123142c6dc6SMarkus Schneider-Pargmann 		.name = "4552",
124142c6dc6SMarkus Schneider-Pargmann 		.id2_register = 0x32353534,
125142c6dc6SMarkus Schneider-Pargmann 	},
126142c6dc6SMarkus Schneider-Pargmann 	[TCAN4553] = {
127142c6dc6SMarkus Schneider-Pargmann 		.name = "4553",
128*a9967c9aSMarkus Schneider-Pargmann 		.id2_register = 0x33353534,
129142c6dc6SMarkus Schneider-Pargmann 	},
130142c6dc6SMarkus Schneider-Pargmann 	/* generic version with no id2_register at the end */
131142c6dc6SMarkus Schneider-Pargmann 	[TCAN4X5X] = {
132142c6dc6SMarkus Schneider-Pargmann 		.name = "generic",
133142c6dc6SMarkus Schneider-Pargmann 		.has_wake_pin = true,
134142c6dc6SMarkus Schneider-Pargmann 		.has_state_pin = true,
135142c6dc6SMarkus Schneider-Pargmann 	},
136142c6dc6SMarkus Schneider-Pargmann };
137142c6dc6SMarkus Schneider-Pargmann 
cdev_to_priv(struct m_can_classdev * cdev)1387813887eSMarc Kleine-Budde static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev)
1397813887eSMarc Kleine-Budde {
1407813887eSMarc Kleine-Budde 	return container_of(cdev, struct tcan4x5x_priv, cdev);
1417813887eSMarc Kleine-Budde }
1427813887eSMarc Kleine-Budde 
tcan4x5x_check_wake(struct tcan4x5x_priv * priv)1437813887eSMarc Kleine-Budde static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv)
1447813887eSMarc Kleine-Budde {
1457813887eSMarc Kleine-Budde 	int wake_state = 0;
1467813887eSMarc Kleine-Budde 
1477813887eSMarc Kleine-Budde 	if (priv->device_state_gpio)
1487813887eSMarc Kleine-Budde 		wake_state = gpiod_get_value(priv->device_state_gpio);
1497813887eSMarc Kleine-Budde 
1507813887eSMarc Kleine-Budde 	if (priv->device_wake_gpio && wake_state) {
1517813887eSMarc Kleine-Budde 		gpiod_set_value(priv->device_wake_gpio, 0);
1527813887eSMarc Kleine-Budde 		usleep_range(5, 50);
1537813887eSMarc Kleine-Budde 		gpiod_set_value(priv->device_wake_gpio, 1);
1547813887eSMarc Kleine-Budde 	}
1557813887eSMarc Kleine-Budde }
1567813887eSMarc Kleine-Budde 
tcan4x5x_reset(struct tcan4x5x_priv * priv)1577813887eSMarc Kleine-Budde static int tcan4x5x_reset(struct tcan4x5x_priv *priv)
1587813887eSMarc Kleine-Budde {
1597813887eSMarc Kleine-Budde 	int ret = 0;
1607813887eSMarc Kleine-Budde 
1617813887eSMarc Kleine-Budde 	if (priv->reset_gpio) {
1627813887eSMarc Kleine-Budde 		gpiod_set_value(priv->reset_gpio, 1);
1637813887eSMarc Kleine-Budde 
1647813887eSMarc Kleine-Budde 		/* tpulse_width minimum 30us */
1657813887eSMarc Kleine-Budde 		usleep_range(30, 100);
1667813887eSMarc Kleine-Budde 		gpiod_set_value(priv->reset_gpio, 0);
1677813887eSMarc Kleine-Budde 	} else {
1687813887eSMarc Kleine-Budde 		ret = regmap_write(priv->regmap, TCAN4X5X_CONFIG,
1697813887eSMarc Kleine-Budde 				   TCAN4X5X_SW_RESET);
1707813887eSMarc Kleine-Budde 		if (ret)
1717813887eSMarc Kleine-Budde 			return ret;
1727813887eSMarc Kleine-Budde 	}
1737813887eSMarc Kleine-Budde 
1747813887eSMarc Kleine-Budde 	usleep_range(700, 1000);
1757813887eSMarc Kleine-Budde 
1767813887eSMarc Kleine-Budde 	return ret;
1777813887eSMarc Kleine-Budde }
1787813887eSMarc Kleine-Budde 
tcan4x5x_read_reg(struct m_can_classdev * cdev,int reg)1797813887eSMarc Kleine-Budde static u32 tcan4x5x_read_reg(struct m_can_classdev *cdev, int reg)
1807813887eSMarc Kleine-Budde {
1817813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
1827813887eSMarc Kleine-Budde 	u32 val;
1837813887eSMarc Kleine-Budde 
1847813887eSMarc Kleine-Budde 	regmap_read(priv->regmap, TCAN4X5X_MCAN_OFFSET + reg, &val);
1857813887eSMarc Kleine-Budde 
1867813887eSMarc Kleine-Budde 	return val;
1877813887eSMarc Kleine-Budde }
1887813887eSMarc Kleine-Budde 
tcan4x5x_read_fifo(struct m_can_classdev * cdev,int addr_offset,void * val,size_t val_count)189e3938177SMatt Kline static int tcan4x5x_read_fifo(struct m_can_classdev *cdev, int addr_offset,
190e3938177SMatt Kline 			      void *val, size_t val_count)
1917813887eSMarc Kleine-Budde {
1927813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
1937813887eSMarc Kleine-Budde 
194e3938177SMatt Kline 	return regmap_bulk_read(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val, val_count);
1957813887eSMarc Kleine-Budde }
1967813887eSMarc Kleine-Budde 
tcan4x5x_write_reg(struct m_can_classdev * cdev,int reg,int val)1977813887eSMarc Kleine-Budde static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val)
1987813887eSMarc Kleine-Budde {
1997813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
2007813887eSMarc Kleine-Budde 
2017813887eSMarc Kleine-Budde 	return regmap_write(priv->regmap, TCAN4X5X_MCAN_OFFSET + reg, val);
2027813887eSMarc Kleine-Budde }
2037813887eSMarc Kleine-Budde 
tcan4x5x_write_fifo(struct m_can_classdev * cdev,int addr_offset,const void * val,size_t val_count)2047813887eSMarc Kleine-Budde static int tcan4x5x_write_fifo(struct m_can_classdev *cdev,
205e3938177SMatt Kline 			       int addr_offset, const void *val, size_t val_count)
2067813887eSMarc Kleine-Budde {
2077813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
2087813887eSMarc Kleine-Budde 
209e3938177SMatt Kline 	return regmap_bulk_write(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val, val_count);
2107813887eSMarc Kleine-Budde }
2117813887eSMarc Kleine-Budde 
tcan4x5x_power_enable(struct regulator * reg,int enable)2127813887eSMarc Kleine-Budde static int tcan4x5x_power_enable(struct regulator *reg, int enable)
2137813887eSMarc Kleine-Budde {
2147813887eSMarc Kleine-Budde 	if (IS_ERR_OR_NULL(reg))
2157813887eSMarc Kleine-Budde 		return 0;
2167813887eSMarc Kleine-Budde 
2177813887eSMarc Kleine-Budde 	if (enable)
2187813887eSMarc Kleine-Budde 		return regulator_enable(reg);
2197813887eSMarc Kleine-Budde 	else
2207813887eSMarc Kleine-Budde 		return regulator_disable(reg);
2217813887eSMarc Kleine-Budde }
2227813887eSMarc Kleine-Budde 
tcan4x5x_write_tcan_reg(struct m_can_classdev * cdev,int reg,int val)2237813887eSMarc Kleine-Budde static int tcan4x5x_write_tcan_reg(struct m_can_classdev *cdev,
2247813887eSMarc Kleine-Budde 				   int reg, int val)
2257813887eSMarc Kleine-Budde {
2267813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
2277813887eSMarc Kleine-Budde 
2287813887eSMarc Kleine-Budde 	return regmap_write(priv->regmap, reg, val);
2297813887eSMarc Kleine-Budde }
2307813887eSMarc Kleine-Budde 
tcan4x5x_clear_interrupts(struct m_can_classdev * cdev)2317813887eSMarc Kleine-Budde static int tcan4x5x_clear_interrupts(struct m_can_classdev *cdev)
2327813887eSMarc Kleine-Budde {
2337813887eSMarc Kleine-Budde 	int ret;
2347813887eSMarc Kleine-Budde 
2357813887eSMarc Kleine-Budde 	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_STATUS,
2367813887eSMarc Kleine-Budde 				      TCAN4X5X_CLEAR_ALL_INT);
2377813887eSMarc Kleine-Budde 	if (ret)
2387813887eSMarc Kleine-Budde 		return ret;
2397813887eSMarc Kleine-Budde 
24067727a17SMarkus Schneider-Pargmann 	return tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_FLAGS,
2417813887eSMarc Kleine-Budde 				       TCAN4X5X_CLEAR_ALL_INT);
2427813887eSMarc Kleine-Budde }
2437813887eSMarc Kleine-Budde 
tcan4x5x_init(struct m_can_classdev * cdev)2447813887eSMarc Kleine-Budde static int tcan4x5x_init(struct m_can_classdev *cdev)
2457813887eSMarc Kleine-Budde {
2467813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
2477813887eSMarc Kleine-Budde 	int ret;
2487813887eSMarc Kleine-Budde 
2497813887eSMarc Kleine-Budde 	tcan4x5x_check_wake(tcan4x5x);
2507813887eSMarc Kleine-Budde 
2517813887eSMarc Kleine-Budde 	ret = tcan4x5x_clear_interrupts(cdev);
2527813887eSMarc Kleine-Budde 	if (ret)
2537813887eSMarc Kleine-Budde 		return ret;
2547813887eSMarc Kleine-Budde 
2557813887eSMarc Kleine-Budde 	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_EN,
2567813887eSMarc Kleine-Budde 				      TCAN4X5X_ENABLE_TCAN_INT);
2577813887eSMarc Kleine-Budde 	if (ret)
2587813887eSMarc Kleine-Budde 		return ret;
2597813887eSMarc Kleine-Budde 
26067727a17SMarkus Schneider-Pargmann 	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS_MASK,
26167727a17SMarkus Schneider-Pargmann 				      TCAN4X5X_CLEAR_ALL_INT);
26267727a17SMarkus Schneider-Pargmann 	if (ret)
26367727a17SMarkus Schneider-Pargmann 		return ret;
26467727a17SMarkus Schneider-Pargmann 
2657813887eSMarc Kleine-Budde 	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
2667813887eSMarc Kleine-Budde 				 TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
2677813887eSMarc Kleine-Budde 	if (ret)
2687813887eSMarc Kleine-Budde 		return ret;
2697813887eSMarc Kleine-Budde 
2707813887eSMarc Kleine-Budde 	return ret;
2717813887eSMarc Kleine-Budde }
2727813887eSMarc Kleine-Budde 
tcan4x5x_disable_wake(struct m_can_classdev * cdev)2737813887eSMarc Kleine-Budde static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
2747813887eSMarc Kleine-Budde {
2757813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
2767813887eSMarc Kleine-Budde 
2777813887eSMarc Kleine-Budde 	return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
2787813887eSMarc Kleine-Budde 				  TCAN4X5X_DISABLE_WAKE_MSK, 0x00);
2797813887eSMarc Kleine-Budde }
2807813887eSMarc Kleine-Budde 
tcan4x5x_disable_state(struct m_can_classdev * cdev)2817813887eSMarc Kleine-Budde static int tcan4x5x_disable_state(struct m_can_classdev *cdev)
2827813887eSMarc Kleine-Budde {
2837813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
2847813887eSMarc Kleine-Budde 
2857813887eSMarc Kleine-Budde 	return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
2867813887eSMarc Kleine-Budde 				  TCAN4X5X_DISABLE_INH_MSK, 0x01);
2877813887eSMarc Kleine-Budde }
2887813887eSMarc Kleine-Budde 
289142c6dc6SMarkus Schneider-Pargmann static const struct tcan4x5x_version_info
tcan4x5x_find_version(struct tcan4x5x_priv * priv)290142c6dc6SMarkus Schneider-Pargmann *tcan4x5x_find_version(struct tcan4x5x_priv *priv)
291142c6dc6SMarkus Schneider-Pargmann {
292142c6dc6SMarkus Schneider-Pargmann 	u32 val;
293142c6dc6SMarkus Schneider-Pargmann 	int ret;
294142c6dc6SMarkus Schneider-Pargmann 
295142c6dc6SMarkus Schneider-Pargmann 	ret = regmap_read(priv->regmap, TCAN4X5X_DEV_ID1, &val);
296142c6dc6SMarkus Schneider-Pargmann 	if (ret)
297142c6dc6SMarkus Schneider-Pargmann 		return ERR_PTR(ret);
298142c6dc6SMarkus Schneider-Pargmann 
299142c6dc6SMarkus Schneider-Pargmann 	if (val != TCAN4X5X_DEV_ID1_TCAN) {
300142c6dc6SMarkus Schneider-Pargmann 		dev_err(&priv->spi->dev, "Not a tcan device %x\n", val);
301142c6dc6SMarkus Schneider-Pargmann 		return ERR_PTR(-ENODEV);
302142c6dc6SMarkus Schneider-Pargmann 	}
303142c6dc6SMarkus Schneider-Pargmann 
304142c6dc6SMarkus Schneider-Pargmann 	ret = regmap_read(priv->regmap, TCAN4X5X_DEV_ID2, &val);
305142c6dc6SMarkus Schneider-Pargmann 	if (ret)
306142c6dc6SMarkus Schneider-Pargmann 		return ERR_PTR(ret);
307142c6dc6SMarkus Schneider-Pargmann 
308142c6dc6SMarkus Schneider-Pargmann 	for (int i = 0; i != ARRAY_SIZE(tcan4x5x_versions); ++i) {
309142c6dc6SMarkus Schneider-Pargmann 		const struct tcan4x5x_version_info *vinfo = &tcan4x5x_versions[i];
310142c6dc6SMarkus Schneider-Pargmann 
311142c6dc6SMarkus Schneider-Pargmann 		if (!vinfo->id2_register || val == vinfo->id2_register) {
312142c6dc6SMarkus Schneider-Pargmann 			dev_info(&priv->spi->dev, "Detected TCAN device version %s\n",
313142c6dc6SMarkus Schneider-Pargmann 				 vinfo->name);
314142c6dc6SMarkus Schneider-Pargmann 			return vinfo;
315142c6dc6SMarkus Schneider-Pargmann 		}
316142c6dc6SMarkus Schneider-Pargmann 	}
317142c6dc6SMarkus Schneider-Pargmann 
318142c6dc6SMarkus Schneider-Pargmann 	return &tcan4x5x_versions[TCAN4X5X];
319142c6dc6SMarkus Schneider-Pargmann }
320142c6dc6SMarkus Schneider-Pargmann 
tcan4x5x_get_gpios(struct m_can_classdev * cdev,const struct tcan4x5x_version_info * version_info)321142c6dc6SMarkus Schneider-Pargmann static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
322142c6dc6SMarkus Schneider-Pargmann 			      const struct tcan4x5x_version_info *version_info)
3237813887eSMarc Kleine-Budde {
3247813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
3257813887eSMarc Kleine-Budde 	int ret;
3267813887eSMarc Kleine-Budde 
327142c6dc6SMarkus Schneider-Pargmann 	if (version_info->has_wake_pin) {
3287813887eSMarc Kleine-Budde 		tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
3297813887eSMarc Kleine-Budde 							    GPIOD_OUT_HIGH);
3307813887eSMarc Kleine-Budde 		if (IS_ERR(tcan4x5x->device_wake_gpio)) {
3317813887eSMarc Kleine-Budde 			if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
3327813887eSMarc Kleine-Budde 				return -EPROBE_DEFER;
3337813887eSMarc Kleine-Budde 
3347813887eSMarc Kleine-Budde 			tcan4x5x_disable_wake(cdev);
3357813887eSMarc Kleine-Budde 		}
336142c6dc6SMarkus Schneider-Pargmann 	}
3377813887eSMarc Kleine-Budde 
3387813887eSMarc Kleine-Budde 	tcan4x5x->reset_gpio = devm_gpiod_get_optional(cdev->dev, "reset",
3397813887eSMarc Kleine-Budde 						       GPIOD_OUT_LOW);
3407813887eSMarc Kleine-Budde 	if (IS_ERR(tcan4x5x->reset_gpio))
3417813887eSMarc Kleine-Budde 		tcan4x5x->reset_gpio = NULL;
3427813887eSMarc Kleine-Budde 
3437813887eSMarc Kleine-Budde 	ret = tcan4x5x_reset(tcan4x5x);
3447813887eSMarc Kleine-Budde 	if (ret)
3457813887eSMarc Kleine-Budde 		return ret;
3467813887eSMarc Kleine-Budde 
347142c6dc6SMarkus Schneider-Pargmann 	if (version_info->has_state_pin) {
3487813887eSMarc Kleine-Budde 		tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
3497813887eSMarc Kleine-Budde 								      "device-state",
3507813887eSMarc Kleine-Budde 								      GPIOD_IN);
3517813887eSMarc Kleine-Budde 		if (IS_ERR(tcan4x5x->device_state_gpio)) {
3527813887eSMarc Kleine-Budde 			tcan4x5x->device_state_gpio = NULL;
3537813887eSMarc Kleine-Budde 			tcan4x5x_disable_state(cdev);
3547813887eSMarc Kleine-Budde 		}
355142c6dc6SMarkus Schneider-Pargmann 	}
3567813887eSMarc Kleine-Budde 
3577813887eSMarc Kleine-Budde 	return 0;
3587813887eSMarc Kleine-Budde }
3597813887eSMarc Kleine-Budde 
3607813887eSMarc Kleine-Budde static struct m_can_ops tcan4x5x_ops = {
3617813887eSMarc Kleine-Budde 	.init = tcan4x5x_init,
3627813887eSMarc Kleine-Budde 	.read_reg = tcan4x5x_read_reg,
3637813887eSMarc Kleine-Budde 	.write_reg = tcan4x5x_write_reg,
3647813887eSMarc Kleine-Budde 	.write_fifo = tcan4x5x_write_fifo,
3657813887eSMarc Kleine-Budde 	.read_fifo = tcan4x5x_read_fifo,
3667813887eSMarc Kleine-Budde 	.clear_interrupts = tcan4x5x_clear_interrupts,
3677813887eSMarc Kleine-Budde };
3687813887eSMarc Kleine-Budde 
tcan4x5x_can_probe(struct spi_device * spi)3697813887eSMarc Kleine-Budde static int tcan4x5x_can_probe(struct spi_device *spi)
3707813887eSMarc Kleine-Budde {
371142c6dc6SMarkus Schneider-Pargmann 	const struct tcan4x5x_version_info *version_info;
3727813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv;
3737813887eSMarc Kleine-Budde 	struct m_can_classdev *mcan_class;
3747813887eSMarc Kleine-Budde 	int freq, ret;
3757813887eSMarc Kleine-Budde 
3767813887eSMarc Kleine-Budde 	mcan_class = m_can_class_allocate_dev(&spi->dev,
3777813887eSMarc Kleine-Budde 					      sizeof(struct tcan4x5x_priv));
3787813887eSMarc Kleine-Budde 	if (!mcan_class)
3797813887eSMarc Kleine-Budde 		return -ENOMEM;
3807813887eSMarc Kleine-Budde 
381c1b17ea7SMarkus Schneider-Pargmann 	ret = m_can_check_mram_cfg(mcan_class, TCAN4X5X_MRAM_SIZE);
382c1b17ea7SMarkus Schneider-Pargmann 	if (ret)
383c1b17ea7SMarkus Schneider-Pargmann 		goto out_m_can_class_free_dev;
384c1b17ea7SMarkus Schneider-Pargmann 
3857813887eSMarc Kleine-Budde 	priv = cdev_to_priv(mcan_class);
3867813887eSMarc Kleine-Budde 
3877813887eSMarc Kleine-Budde 	priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
3887813887eSMarc Kleine-Budde 	if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
3897813887eSMarc Kleine-Budde 		ret = -EPROBE_DEFER;
3907813887eSMarc Kleine-Budde 		goto out_m_can_class_free_dev;
3917813887eSMarc Kleine-Budde 	} else {
3927813887eSMarc Kleine-Budde 		priv->power = NULL;
3937813887eSMarc Kleine-Budde 	}
3947813887eSMarc Kleine-Budde 
3957813887eSMarc Kleine-Budde 	m_can_class_get_clocks(mcan_class);
3967813887eSMarc Kleine-Budde 	if (IS_ERR(mcan_class->cclk)) {
3977813887eSMarc Kleine-Budde 		dev_err(&spi->dev, "no CAN clock source defined\n");
3987813887eSMarc Kleine-Budde 		freq = TCAN4X5X_EXT_CLK_DEF;
3997813887eSMarc Kleine-Budde 	} else {
4007813887eSMarc Kleine-Budde 		freq = clk_get_rate(mcan_class->cclk);
4017813887eSMarc Kleine-Budde 	}
4027813887eSMarc Kleine-Budde 
4037813887eSMarc Kleine-Budde 	/* Sanity check */
4047813887eSMarc Kleine-Budde 	if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF) {
40535e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "Clock frequency is out of supported range %d\n",
40635e7aaabSMarkus Schneider-Pargmann 			freq);
4077813887eSMarc Kleine-Budde 		ret = -ERANGE;
4087813887eSMarc Kleine-Budde 		goto out_m_can_class_free_dev;
4097813887eSMarc Kleine-Budde 	}
4107813887eSMarc Kleine-Budde 
4117813887eSMarc Kleine-Budde 	priv->spi = spi;
4127813887eSMarc Kleine-Budde 
4137813887eSMarc Kleine-Budde 	mcan_class->pm_clock_support = 0;
4147813887eSMarc Kleine-Budde 	mcan_class->can.clock.freq = freq;
4157813887eSMarc Kleine-Budde 	mcan_class->dev = &spi->dev;
4167813887eSMarc Kleine-Budde 	mcan_class->ops = &tcan4x5x_ops;
4177813887eSMarc Kleine-Budde 	mcan_class->is_peripheral = true;
4187813887eSMarc Kleine-Budde 	mcan_class->net->irq = spi->irq;
4197813887eSMarc Kleine-Budde 
4207813887eSMarc Kleine-Budde 	spi_set_drvdata(spi, priv);
4217813887eSMarc Kleine-Budde 
4227813887eSMarc Kleine-Budde 	/* Configure the SPI bus */
4231c5d0fc4SMarc Kleine-Budde 	spi->bits_per_word = 8;
4247813887eSMarc Kleine-Budde 	ret = spi_setup(spi);
42535e7aaabSMarkus Schneider-Pargmann 	if (ret) {
42635e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "SPI setup failed %pe\n", ERR_PTR(ret));
4277813887eSMarc Kleine-Budde 		goto out_m_can_class_free_dev;
42835e7aaabSMarkus Schneider-Pargmann 	}
4297813887eSMarc Kleine-Budde 
43067def4efSMarc Kleine-Budde 	ret = tcan4x5x_regmap_init(priv);
43135e7aaabSMarkus Schneider-Pargmann 	if (ret) {
43235e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "regmap init failed %pe\n", ERR_PTR(ret));
4337813887eSMarc Kleine-Budde 		goto out_m_can_class_free_dev;
43435e7aaabSMarkus Schneider-Pargmann 	}
4357813887eSMarc Kleine-Budde 
4367813887eSMarc Kleine-Budde 	ret = tcan4x5x_power_enable(priv->power, 1);
43735e7aaabSMarkus Schneider-Pargmann 	if (ret) {
43835e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "Enabling regulator failed %pe\n",
43935e7aaabSMarkus Schneider-Pargmann 			ERR_PTR(ret));
4407813887eSMarc Kleine-Budde 		goto out_m_can_class_free_dev;
44135e7aaabSMarkus Schneider-Pargmann 	}
4427813887eSMarc Kleine-Budde 
443142c6dc6SMarkus Schneider-Pargmann 	version_info = tcan4x5x_find_version(priv);
444142c6dc6SMarkus Schneider-Pargmann 	if (IS_ERR(version_info)) {
445142c6dc6SMarkus Schneider-Pargmann 		ret = PTR_ERR(version_info);
446142c6dc6SMarkus Schneider-Pargmann 		goto out_power;
447142c6dc6SMarkus Schneider-Pargmann 	}
448142c6dc6SMarkus Schneider-Pargmann 
449142c6dc6SMarkus Schneider-Pargmann 	ret = tcan4x5x_get_gpios(mcan_class, version_info);
45035e7aaabSMarkus Schneider-Pargmann 	if (ret) {
45135e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "Getting gpios failed %pe\n", ERR_PTR(ret));
4527813887eSMarc Kleine-Budde 		goto out_power;
45335e7aaabSMarkus Schneider-Pargmann 	}
4547813887eSMarc Kleine-Budde 
4557813887eSMarc Kleine-Budde 	ret = tcan4x5x_init(mcan_class);
45635e7aaabSMarkus Schneider-Pargmann 	if (ret) {
45735e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "tcan initialization failed %pe\n",
45835e7aaabSMarkus Schneider-Pargmann 			ERR_PTR(ret));
4597813887eSMarc Kleine-Budde 		goto out_power;
46035e7aaabSMarkus Schneider-Pargmann 	}
4617813887eSMarc Kleine-Budde 
4627813887eSMarc Kleine-Budde 	ret = m_can_class_register(mcan_class);
46335e7aaabSMarkus Schneider-Pargmann 	if (ret) {
46435e7aaabSMarkus Schneider-Pargmann 		dev_err(&spi->dev, "Failed registering m_can device %pe\n",
46535e7aaabSMarkus Schneider-Pargmann 			ERR_PTR(ret));
4667813887eSMarc Kleine-Budde 		goto out_power;
46735e7aaabSMarkus Schneider-Pargmann 	}
4687813887eSMarc Kleine-Budde 
4697813887eSMarc Kleine-Budde 	netdev_info(mcan_class->net, "TCAN4X5X successfully initialized.\n");
4707813887eSMarc Kleine-Budde 	return 0;
4717813887eSMarc Kleine-Budde 
4727813887eSMarc Kleine-Budde out_power:
4737813887eSMarc Kleine-Budde 	tcan4x5x_power_enable(priv->power, 0);
4747813887eSMarc Kleine-Budde  out_m_can_class_free_dev:
4757813887eSMarc Kleine-Budde 	m_can_class_free_dev(mcan_class->net);
4767813887eSMarc Kleine-Budde 	return ret;
4777813887eSMarc Kleine-Budde }
4787813887eSMarc Kleine-Budde 
tcan4x5x_can_remove(struct spi_device * spi)479a0386bbaSUwe Kleine-König static void tcan4x5x_can_remove(struct spi_device *spi)
4807813887eSMarc Kleine-Budde {
4817813887eSMarc Kleine-Budde 	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
4827813887eSMarc Kleine-Budde 
4837813887eSMarc Kleine-Budde 	m_can_class_unregister(&priv->cdev);
4847813887eSMarc Kleine-Budde 
4857813887eSMarc Kleine-Budde 	tcan4x5x_power_enable(priv->power, 0);
4867813887eSMarc Kleine-Budde 
4877813887eSMarc Kleine-Budde 	m_can_class_free_dev(priv->cdev.net);
4887813887eSMarc Kleine-Budde }
4897813887eSMarc Kleine-Budde 
4907813887eSMarc Kleine-Budde static const struct of_device_id tcan4x5x_of_match[] = {
4917813887eSMarc Kleine-Budde 	{
4927813887eSMarc Kleine-Budde 		.compatible = "ti,tcan4x5x",
4937813887eSMarc Kleine-Budde 	}, {
4947813887eSMarc Kleine-Budde 		/* sentinel */
4957813887eSMarc Kleine-Budde 	},
4967813887eSMarc Kleine-Budde };
4977813887eSMarc Kleine-Budde MODULE_DEVICE_TABLE(of, tcan4x5x_of_match);
4987813887eSMarc Kleine-Budde 
4997813887eSMarc Kleine-Budde static const struct spi_device_id tcan4x5x_id_table[] = {
5007813887eSMarc Kleine-Budde 	{
5017813887eSMarc Kleine-Budde 		.name = "tcan4x5x",
5027813887eSMarc Kleine-Budde 	}, {
5037813887eSMarc Kleine-Budde 		/* sentinel */
5047813887eSMarc Kleine-Budde 	},
5057813887eSMarc Kleine-Budde };
5067813887eSMarc Kleine-Budde MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table);
5077813887eSMarc Kleine-Budde 
5087813887eSMarc Kleine-Budde static struct spi_driver tcan4x5x_can_driver = {
5097813887eSMarc Kleine-Budde 	.driver = {
5107813887eSMarc Kleine-Budde 		.name = KBUILD_MODNAME,
5117813887eSMarc Kleine-Budde 		.of_match_table = tcan4x5x_of_match,
5127813887eSMarc Kleine-Budde 		.pm = NULL,
5137813887eSMarc Kleine-Budde 	},
5147813887eSMarc Kleine-Budde 	.id_table = tcan4x5x_id_table,
5157813887eSMarc Kleine-Budde 	.probe = tcan4x5x_can_probe,
5167813887eSMarc Kleine-Budde 	.remove = tcan4x5x_can_remove,
5177813887eSMarc Kleine-Budde };
5187813887eSMarc Kleine-Budde module_spi_driver(tcan4x5x_can_driver);
5197813887eSMarc Kleine-Budde 
5207813887eSMarc Kleine-Budde MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
5217813887eSMarc Kleine-Budde MODULE_DESCRIPTION("Texas Instruments TCAN4x5x CAN driver");
5227813887eSMarc Kleine-Budde MODULE_LICENSE("GPL v2");
523