1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver 4 // 5 // Copyright (c) 2021 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_read(const struct cyclecounter *cc) 15 { 16 const struct mcp251xfd_priv *priv; 17 u32 timestamp = 0; 18 int err; 19 20 priv = container_of(cc, struct mcp251xfd_priv, cc); 21 err = mcp251xfd_get_timestamp(priv, ×tamp); 22 if (err) 23 netdev_err(priv->ndev, 24 "Error %d while reading timestamp. HW timestamps may be inaccurate.", 25 err); 26 27 return timestamp; 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_skb_set_timestamp(const struct mcp251xfd_priv *priv, 43 struct sk_buff *skb, u32 timestamp) 44 { 45 struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); 46 u64 ns; 47 48 ns = timecounter_cyc2time(&priv->tc, timestamp); 49 hwtstamps->hwtstamp = ns_to_ktime(ns); 50 } 51 52 void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv) 53 { 54 struct cyclecounter *cc = &priv->cc; 55 56 cc->read = mcp251xfd_timestamp_read; 57 cc->mask = CYCLECOUNTER_MASK(32); 58 cc->shift = 1; 59 cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift); 60 61 timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns()); 62 63 INIT_DELAYED_WORK(&priv->timestamp, mcp251xfd_timestamp_work); 64 schedule_delayed_work(&priv->timestamp, 65 MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); 66 } 67 68 void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv) 69 { 70 cancel_delayed_work_sync(&priv->timestamp); 71 } 72