1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver 4 // 5 // Copyright (c) 2021, 2023 Pengutronix, 6 // Marc Kleine-Budde <kernel@pengutronix.de> 7 // 8 9 #include <linux/clocksource.h> 10 #include <linux/workqueue.h> 11 12 #include "mcp251xfd.h" 13 14 static u64 mcp251xfd_timestamp_raw_read(const struct cyclecounter *cc) 15 { 16 const struct mcp251xfd_priv *priv; 17 u32 ts_raw = 0; 18 int err; 19 20 priv = container_of(cc, struct mcp251xfd_priv, cc); 21 err = mcp251xfd_get_timestamp_raw(priv, &ts_raw); 22 if (err) 23 netdev_err(priv->ndev, 24 "Error %d while reading timestamp. HW timestamps may be inaccurate.", 25 err); 26 27 return ts_raw; 28 } 29 30 static void mcp251xfd_timestamp_work(struct work_struct *work) 31 { 32 struct delayed_work *delayed_work = to_delayed_work(work); 33 struct mcp251xfd_priv *priv; 34 35 priv = container_of(delayed_work, struct mcp251xfd_priv, timestamp); 36 timecounter_read(&priv->tc); 37 38 schedule_delayed_work(&priv->timestamp, 39 MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); 40 } 41 42 void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv) 43 { 44 struct cyclecounter *cc = &priv->cc; 45 46 cc->read = mcp251xfd_timestamp_raw_read; 47 cc->mask = CYCLECOUNTER_MASK(32); 48 cc->shift = 1; 49 cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift); 50 51 timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns()); 52 53 INIT_DELAYED_WORK(&priv->timestamp, mcp251xfd_timestamp_work); 54 schedule_delayed_work(&priv->timestamp, 55 MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); 56 } 57 58 void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv) 59 { 60 cancel_delayed_work_sync(&priv->timestamp); 61 } 62