Skip to content

Commit 142c6dc

Browse files
scosumarckleinebudde
authored andcommitted
can: tcan4x5x: Add support for tcan4552/4553
tcan4552 and tcan4553 do not have wake or state pins, so they are currently not compatible with the generic driver. The generic driver uses tcan4x5x_disable_state() and tcan4x5x_disable_wake() if the gpios are not defined. These functions use register bits that are not available in tcan4552/4553. This patch adds support by introducing version information to reflect if the chip has wake and state pins. Also the version is now checked. Signed-off-by: Markus Schneider-Pargmann <[email protected]> Link: https://lore.kernel.org/all/[email protected] Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 0d6f3b2 commit 142c6dc

File tree

1 file changed

+90
-14
lines changed

1 file changed

+90
-14
lines changed

drivers/net/can/m_can/tcan4x5x-core.c

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define TCAN4X5X_EXT_CLK_DEF 40000000
88

99
#define TCAN4X5X_DEV_ID1 0x00
10+
#define TCAN4X5X_DEV_ID1_TCAN 0x4e414354 /* ASCII TCAN */
1011
#define TCAN4X5X_DEV_ID2 0x04
1112
#define TCAN4X5X_REV 0x08
1213
#define TCAN4X5X_STATUS 0x0C
@@ -103,6 +104,37 @@
103104
#define TCAN4X5X_WD_3_S_TIMER BIT(29)
104105
#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29))
105106

107+
struct tcan4x5x_version_info {
108+
const char *name;
109+
u32 id2_register;
110+
111+
bool has_wake_pin;
112+
bool has_state_pin;
113+
};
114+
115+
enum {
116+
TCAN4552 = 0,
117+
TCAN4553,
118+
TCAN4X5X,
119+
};
120+
121+
static const struct tcan4x5x_version_info tcan4x5x_versions[] = {
122+
[TCAN4552] = {
123+
.name = "4552",
124+
.id2_register = 0x32353534,
125+
},
126+
[TCAN4553] = {
127+
.name = "4553",
128+
.id2_register = 0x32353534,
129+
},
130+
/* generic version with no id2_register at the end */
131+
[TCAN4X5X] = {
132+
.name = "generic",
133+
.has_wake_pin = true,
134+
.has_state_pin = true,
135+
},
136+
};
137+
106138
static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev)
107139
{
108140
return container_of(cdev, struct tcan4x5x_priv, cdev);
@@ -254,18 +286,53 @@ static int tcan4x5x_disable_state(struct m_can_classdev *cdev)
254286
TCAN4X5X_DISABLE_INH_MSK, 0x01);
255287
}
256288

257-
static int tcan4x5x_get_gpios(struct m_can_classdev *cdev)
289+
static const struct tcan4x5x_version_info
290+
*tcan4x5x_find_version(struct tcan4x5x_priv *priv)
291+
{
292+
u32 val;
293+
int ret;
294+
295+
ret = regmap_read(priv->regmap, TCAN4X5X_DEV_ID1, &val);
296+
if (ret)
297+
return ERR_PTR(ret);
298+
299+
if (val != TCAN4X5X_DEV_ID1_TCAN) {
300+
dev_err(&priv->spi->dev, "Not a tcan device %x\n", val);
301+
return ERR_PTR(-ENODEV);
302+
}
303+
304+
ret = regmap_read(priv->regmap, TCAN4X5X_DEV_ID2, &val);
305+
if (ret)
306+
return ERR_PTR(ret);
307+
308+
for (int i = 0; i != ARRAY_SIZE(tcan4x5x_versions); ++i) {
309+
const struct tcan4x5x_version_info *vinfo = &tcan4x5x_versions[i];
310+
311+
if (!vinfo->id2_register || val == vinfo->id2_register) {
312+
dev_info(&priv->spi->dev, "Detected TCAN device version %s\n",
313+
vinfo->name);
314+
return vinfo;
315+
}
316+
}
317+
318+
return &tcan4x5x_versions[TCAN4X5X];
319+
}
320+
321+
static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
322+
const struct tcan4x5x_version_info *version_info)
258323
{
259324
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
260325
int ret;
261326

262-
tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
263-
GPIOD_OUT_HIGH);
264-
if (IS_ERR(tcan4x5x->device_wake_gpio)) {
265-
if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
266-
return -EPROBE_DEFER;
327+
if (version_info->has_wake_pin) {
328+
tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
329+
GPIOD_OUT_HIGH);
330+
if (IS_ERR(tcan4x5x->device_wake_gpio)) {
331+
if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
332+
return -EPROBE_DEFER;
267333

268-
tcan4x5x_disable_wake(cdev);
334+
tcan4x5x_disable_wake(cdev);
335+
}
269336
}
270337

271338
tcan4x5x->reset_gpio = devm_gpiod_get_optional(cdev->dev, "reset",
@@ -277,12 +344,14 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev)
277344
if (ret)
278345
return ret;
279346

280-
tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
281-
"device-state",
282-
GPIOD_IN);
283-
if (IS_ERR(tcan4x5x->device_state_gpio)) {
284-
tcan4x5x->device_state_gpio = NULL;
285-
tcan4x5x_disable_state(cdev);
347+
if (version_info->has_state_pin) {
348+
tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
349+
"device-state",
350+
GPIOD_IN);
351+
if (IS_ERR(tcan4x5x->device_state_gpio)) {
352+
tcan4x5x->device_state_gpio = NULL;
353+
tcan4x5x_disable_state(cdev);
354+
}
286355
}
287356

288357
return 0;
@@ -299,6 +368,7 @@ static struct m_can_ops tcan4x5x_ops = {
299368

300369
static int tcan4x5x_can_probe(struct spi_device *spi)
301370
{
371+
const struct tcan4x5x_version_info *version_info;
302372
struct tcan4x5x_priv *priv;
303373
struct m_can_classdev *mcan_class;
304374
int freq, ret;
@@ -361,7 +431,13 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
361431
if (ret)
362432
goto out_m_can_class_free_dev;
363433

364-
ret = tcan4x5x_get_gpios(mcan_class);
434+
version_info = tcan4x5x_find_version(priv);
435+
if (IS_ERR(version_info)) {
436+
ret = PTR_ERR(version_info);
437+
goto out_power;
438+
}
439+
440+
ret = tcan4x5x_get_gpios(mcan_class, version_info);
365441
if (ret)
366442
goto out_power;
367443

0 commit comments

Comments
 (0)