linux/drivers/net/ethernet/ti/cpts.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * TI Common Platform Time Sync
   4 *
   5 * Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
   6 *
   7 */
   8#include <linux/clk-provider.h>
   9#include <linux/err.h>
  10#include <linux/if.h>
  11#include <linux/hrtimer.h>
  12#include <linux/module.h>
  13#include <linux/net_tstamp.h>
  14#include <linux/ptp_classify.h>
  15#include <linux/time.h>
  16#include <linux/uaccess.h>
  17#include <linux/workqueue.h>
  18#include <linux/if_ether.h>
  19#include <linux/if_vlan.h>
  20
  21#include "cpts.h"
  22
  23#define CPTS_SKB_TX_WORK_TIMEOUT 1 /* jiffies */
  24
  25struct cpts_skb_cb_data {
  26        unsigned long tmo;
  27};
  28
  29#define cpts_read32(c, r)       readl_relaxed(&c->reg->r)
  30#define cpts_write32(c, v, r)   writel_relaxed(v, &c->reg->r)
  31
  32static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
  33                      u16 ts_seqid, u8 ts_msgtype);
  34
  35static int event_expired(struct cpts_event *event)
  36{
  37        return time_after(jiffies, event->tmo);
  38}
  39
  40static int event_type(struct cpts_event *event)
  41{
  42        return (event->high >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK;
  43}
  44
  45static int cpts_fifo_pop(struct cpts *cpts, u32 *high, u32 *low)
  46{
  47        u32 r = cpts_read32(cpts, intstat_raw);
  48
  49        if (r & TS_PEND_RAW) {
  50                *high = cpts_read32(cpts, event_high);
  51                *low  = cpts_read32(cpts, event_low);
  52                cpts_write32(cpts, EVENT_POP, event_pop);
  53                return 0;
  54        }
  55        return -1;
  56}
  57
  58static int cpts_purge_events(struct cpts *cpts)
  59{
  60        struct list_head *this, *next;
  61        struct cpts_event *event;
  62        int removed = 0;
  63
  64        list_for_each_safe(this, next, &cpts->events) {
  65                event = list_entry(this, struct cpts_event, list);
  66                if (event_expired(event)) {
  67                        list_del_init(&event->list);
  68                        list_add(&event->list, &cpts->pool);
  69                        ++removed;
  70                }
  71        }
  72
  73        if (removed)
  74                pr_debug("cpts: event pool cleaned up %d\n", removed);
  75        return removed ? 0 : -1;
  76}
  77
  78static void cpts_purge_txq(struct cpts *cpts)
  79{
  80        struct cpts_skb_cb_data *skb_cb;
  81        struct sk_buff *skb, *tmp;
  82        int removed = 0;
  83
  84        skb_queue_walk_safe(&cpts->txq, skb, tmp) {
  85                skb_cb = (struct cpts_skb_cb_data *)skb->cb;
  86                if (time_after(jiffies, skb_cb->tmo)) {
  87                        __skb_unlink(skb, &cpts->txq);
  88                        dev_consume_skb_any(skb);
  89                        ++removed;
  90                }
  91        }
  92
  93        if (removed)
  94                dev_dbg(cpts->dev, "txq cleaned up %d\n", removed);
  95}
  96
  97static bool cpts_match_tx_ts(struct cpts *cpts, struct cpts_event *event)
  98{
  99        struct sk_buff *skb, *tmp;
 100        u16 seqid;
 101        u8 mtype;
 102        bool found = false;
 103
 104        mtype = (event->high >> MESSAGE_TYPE_SHIFT) & MESSAGE_TYPE_MASK;
 105        seqid = (event->high >> SEQUENCE_ID_SHIFT) & SEQUENCE_ID_MASK;
 106
 107        /* no need to grab txq.lock as access is always done under cpts->lock */
 108        skb_queue_walk_safe(&cpts->txq, skb, tmp) {
 109                struct skb_shared_hwtstamps ssh;
 110                unsigned int class = ptp_classify_raw(skb);
 111                struct cpts_skb_cb_data *skb_cb =
 112                                        (struct cpts_skb_cb_data *)skb->cb;
 113
 114                if (cpts_match(skb, class, seqid, mtype)) {
 115                        u64 ns = timecounter_cyc2time(&cpts->tc, event->low);
 116
 117                        memset(&ssh, 0, sizeof(ssh));
 118                        ssh.hwtstamp = ns_to_ktime(ns);
 119                        skb_tstamp_tx(skb, &ssh);
 120                        found = true;
 121                        __skb_unlink(skb, &cpts->txq);
 122                        dev_consume_skb_any(skb);
 123                        dev_dbg(cpts->dev, "match tx timestamp mtype %u seqid %04x\n",
 124                                mtype, seqid);
 125                        break;
 126                }
 127
 128                if (time_after(jiffies, skb_cb->tmo)) {
 129                        /* timeout any expired skbs over 1s */
 130                        dev_dbg(cpts->dev, "expiring tx timestamp from txq\n");
 131                        __skb_unlink(skb, &cpts->txq);
 132                        dev_consume_skb_any(skb);
 133                }
 134        }
 135
 136        return found;
 137}
 138
 139/*
 140 * Returns zero if matching event type was found.
 141 */
 142static int cpts_fifo_read(struct cpts *cpts, int match)
 143{
 144        int i, type = -1;
 145        u32 hi, lo;
 146        struct cpts_event *event;
 147
 148        for (i = 0; i < CPTS_FIFO_DEPTH; i++) {
 149                if (cpts_fifo_pop(cpts, &hi, &lo))
 150                        break;
 151
 152                if (list_empty(&cpts->pool) && cpts_purge_events(cpts)) {
 153                        pr_err("cpts: event pool empty\n");
 154                        return -1;
 155                }
 156
 157                event = list_first_entry(&cpts->pool, struct cpts_event, list);
 158                event->tmo = jiffies + 2;
 159                event->high = hi;
 160                event->low = lo;
 161                type = event_type(event);
 162                switch (type) {
 163                case CPTS_EV_TX:
 164                        if (cpts_match_tx_ts(cpts, event)) {
 165                                /* if the new event matches an existing skb,
 166                                 * then don't queue it
 167                                 */
 168                                break;
 169                        }
 170                        /* fall through */
 171                case CPTS_EV_PUSH:
 172                case CPTS_EV_RX:
 173                        list_del_init(&event->list);
 174                        list_add_tail(&event->list, &cpts->events);
 175                        break;
 176                case CPTS_EV_ROLL:
 177                case CPTS_EV_HALF:
 178                case CPTS_EV_HW:
 179                        break;
 180                default:
 181                        pr_err("cpts: unknown event type\n");
 182                        break;
 183                }
 184                if (type == match)
 185                        break;
 186        }
 187        return type == match ? 0 : -1;
 188}
 189
 190static u64 cpts_systim_read(const struct cyclecounter *cc)
 191{
 192        u64 val = 0;
 193        struct cpts_event *event;
 194        struct list_head *this, *next;
 195        struct cpts *cpts = container_of(cc, struct cpts, cc);
 196
 197        cpts_write32(cpts, TS_PUSH, ts_push);
 198        if (cpts_fifo_read(cpts, CPTS_EV_PUSH))
 199                pr_err("cpts: unable to obtain a time stamp\n");
 200
 201        list_for_each_safe(this, next, &cpts->events) {
 202                event = list_entry(this, struct cpts_event, list);
 203                if (event_type(event) == CPTS_EV_PUSH) {
 204                        list_del_init(&event->list);
 205                        list_add(&event->list, &cpts->pool);
 206                        val = event->low;
 207                        break;
 208                }
 209        }
 210
 211        return val;
 212}
 213
 214/* PTP clock operations */
 215
 216static int cpts_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
 217{
 218        u64 adj;
 219        u32 diff, mult;
 220        int neg_adj = 0;
 221        unsigned long flags;
 222        struct cpts *cpts = container_of(ptp, struct cpts, info);
 223
 224        if (ppb < 0) {
 225                neg_adj = 1;
 226                ppb = -ppb;
 227        }
 228        mult = cpts->cc_mult;
 229        adj = mult;
 230        adj *= ppb;
 231        diff = div_u64(adj, 1000000000ULL);
 232
 233        spin_lock_irqsave(&cpts->lock, flags);
 234
 235        timecounter_read(&cpts->tc);
 236
 237        cpts->cc.mult = neg_adj ? mult - diff : mult + diff;
 238
 239        spin_unlock_irqrestore(&cpts->lock, flags);
 240
 241        return 0;
 242}
 243
 244static int cpts_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 245{
 246        unsigned long flags;
 247        struct cpts *cpts = container_of(ptp, struct cpts, info);
 248
 249        spin_lock_irqsave(&cpts->lock, flags);
 250        timecounter_adjtime(&cpts->tc, delta);
 251        spin_unlock_irqrestore(&cpts->lock, flags);
 252
 253        return 0;
 254}
 255
 256static int cpts_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
 257{
 258        u64 ns;
 259        unsigned long flags;
 260        struct cpts *cpts = container_of(ptp, struct cpts, info);
 261
 262        spin_lock_irqsave(&cpts->lock, flags);
 263        ns = timecounter_read(&cpts->tc);
 264        spin_unlock_irqrestore(&cpts->lock, flags);
 265
 266        *ts = ns_to_timespec64(ns);
 267
 268        return 0;
 269}
 270
 271static int cpts_ptp_settime(struct ptp_clock_info *ptp,
 272                            const struct timespec64 *ts)
 273{
 274        u64 ns;
 275        unsigned long flags;
 276        struct cpts *cpts = container_of(ptp, struct cpts, info);
 277
 278        ns = timespec64_to_ns(ts);
 279
 280        spin_lock_irqsave(&cpts->lock, flags);
 281        timecounter_init(&cpts->tc, &cpts->cc, ns);
 282        spin_unlock_irqrestore(&cpts->lock, flags);
 283
 284        return 0;
 285}
 286
 287static int cpts_ptp_enable(struct ptp_clock_info *ptp,
 288                           struct ptp_clock_request *rq, int on)
 289{
 290        return -EOPNOTSUPP;
 291}
 292
 293static long cpts_overflow_check(struct ptp_clock_info *ptp)
 294{
 295        struct cpts *cpts = container_of(ptp, struct cpts, info);
 296        unsigned long delay = cpts->ov_check_period;
 297        struct timespec64 ts;
 298        unsigned long flags;
 299
 300        spin_lock_irqsave(&cpts->lock, flags);
 301        ts = ns_to_timespec64(timecounter_read(&cpts->tc));
 302
 303        if (!skb_queue_empty(&cpts->txq)) {
 304                cpts_purge_txq(cpts);
 305                if (!skb_queue_empty(&cpts->txq))
 306                        delay = CPTS_SKB_TX_WORK_TIMEOUT;
 307        }
 308        spin_unlock_irqrestore(&cpts->lock, flags);
 309
 310        pr_debug("cpts overflow check at %lld.%09ld\n",
 311                 (long long)ts.tv_sec, ts.tv_nsec);
 312        return (long)delay;
 313}
 314
 315static const struct ptp_clock_info cpts_info = {
 316        .owner          = THIS_MODULE,
 317        .name           = "CTPS timer",
 318        .max_adj        = 1000000,
 319        .n_ext_ts       = 0,
 320        .n_pins         = 0,
 321        .pps            = 0,
 322        .adjfreq        = cpts_ptp_adjfreq,
 323        .adjtime        = cpts_ptp_adjtime,
 324        .gettime64      = cpts_ptp_gettime,
 325        .settime64      = cpts_ptp_settime,
 326        .enable         = cpts_ptp_enable,
 327        .do_aux_work    = cpts_overflow_check,
 328};
 329
 330static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
 331                      u16 ts_seqid, u8 ts_msgtype)
 332{
 333        u16 *seqid;
 334        unsigned int offset = 0;
 335        u8 *msgtype, *data = skb->data;
 336
 337        if (ptp_class & PTP_CLASS_VLAN)
 338                offset += VLAN_HLEN;
 339
 340        switch (ptp_class & PTP_CLASS_PMASK) {
 341        case PTP_CLASS_IPV4:
 342                offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
 343                break;
 344        case PTP_CLASS_IPV6:
 345                offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
 346                break;
 347        case PTP_CLASS_L2:
 348                offset += ETH_HLEN;
 349                break;
 350        default:
 351                return 0;
 352        }
 353
 354        if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
 355                return 0;
 356
 357        if (unlikely(ptp_class & PTP_CLASS_V1))
 358                msgtype = data + offset + OFF_PTP_CONTROL;
 359        else
 360                msgtype = data + offset;
 361
 362        seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
 363
 364        return (ts_msgtype == (*msgtype & 0xf) && ts_seqid == ntohs(*seqid));
 365}
 366
 367static u64 cpts_find_ts(struct cpts *cpts, struct sk_buff *skb, int ev_type)
 368{
 369        u64 ns = 0;
 370        struct cpts_event *event;
 371        struct list_head *this, *next;
 372        unsigned int class = ptp_classify_raw(skb);
 373        unsigned long flags;
 374        u16 seqid;
 375        u8 mtype;
 376
 377        if (class == PTP_CLASS_NONE)
 378                return 0;
 379
 380        spin_lock_irqsave(&cpts->lock, flags);
 381        cpts_fifo_read(cpts, -1);
 382        list_for_each_safe(this, next, &cpts->events) {
 383                event = list_entry(this, struct cpts_event, list);
 384                if (event_expired(event)) {
 385                        list_del_init(&event->list);
 386                        list_add(&event->list, &cpts->pool);
 387                        continue;
 388                }
 389                mtype = (event->high >> MESSAGE_TYPE_SHIFT) & MESSAGE_TYPE_MASK;
 390                seqid = (event->high >> SEQUENCE_ID_SHIFT) & SEQUENCE_ID_MASK;
 391                if (ev_type == event_type(event) &&
 392                    cpts_match(skb, class, seqid, mtype)) {
 393                        ns = timecounter_cyc2time(&cpts->tc, event->low);
 394                        list_del_init(&event->list);
 395                        list_add(&event->list, &cpts->pool);
 396                        break;
 397                }
 398        }
 399
 400        if (ev_type == CPTS_EV_TX && !ns) {
 401                struct cpts_skb_cb_data *skb_cb =
 402                                (struct cpts_skb_cb_data *)skb->cb;
 403                /* Not found, add frame to queue for processing later.
 404                 * The periodic FIFO check will handle this.
 405                 */
 406                skb_get(skb);
 407                /* get the timestamp for timeouts */
 408                skb_cb->tmo = jiffies + msecs_to_jiffies(100);
 409                __skb_queue_tail(&cpts->txq, skb);
 410                ptp_schedule_worker(cpts->clock, 0);
 411        }
 412        spin_unlock_irqrestore(&cpts->lock, flags);
 413
 414        return ns;
 415}
 416
 417void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 418{
 419        u64 ns;
 420        struct skb_shared_hwtstamps *ssh;
 421
 422        ns = cpts_find_ts(cpts, skb, CPTS_EV_RX);
 423        if (!ns)
 424                return;
 425        ssh = skb_hwtstamps(skb);
 426        memset(ssh, 0, sizeof(*ssh));
 427        ssh->hwtstamp = ns_to_ktime(ns);
 428}
 429EXPORT_SYMBOL_GPL(cpts_rx_timestamp);
 430
 431void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 432{
 433        u64 ns;
 434        struct skb_shared_hwtstamps ssh;
 435
 436        if (!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
 437                return;
 438        ns = cpts_find_ts(cpts, skb, CPTS_EV_TX);
 439        if (!ns)
 440                return;
 441        memset(&ssh, 0, sizeof(ssh));
 442        ssh.hwtstamp = ns_to_ktime(ns);
 443        skb_tstamp_tx(skb, &ssh);
 444}
 445EXPORT_SYMBOL_GPL(cpts_tx_timestamp);
 446
 447int cpts_register(struct cpts *cpts)
 448{
 449        int err, i;
 450
 451        skb_queue_head_init(&cpts->txq);
 452        INIT_LIST_HEAD(&cpts->events);
 453        INIT_LIST_HEAD(&cpts->pool);
 454        for (i = 0; i < CPTS_MAX_EVENTS; i++)
 455                list_add(&cpts->pool_data[i].list, &cpts->pool);
 456
 457        clk_enable(cpts->refclk);
 458
 459        cpts_write32(cpts, CPTS_EN, control);
 460        cpts_write32(cpts, TS_PEND_EN, int_enable);
 461
 462        timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real()));
 463
 464        cpts->clock = ptp_clock_register(&cpts->info, cpts->dev);
 465        if (IS_ERR(cpts->clock)) {
 466                err = PTR_ERR(cpts->clock);
 467                cpts->clock = NULL;
 468                goto err_ptp;
 469        }
 470        cpts->phc_index = ptp_clock_index(cpts->clock);
 471
 472        ptp_schedule_worker(cpts->clock, cpts->ov_check_period);
 473        return 0;
 474
 475err_ptp:
 476        clk_disable(cpts->refclk);
 477        return err;
 478}
 479EXPORT_SYMBOL_GPL(cpts_register);
 480
 481void cpts_unregister(struct cpts *cpts)
 482{
 483        if (WARN_ON(!cpts->clock))
 484                return;
 485
 486        ptp_clock_unregister(cpts->clock);
 487        cpts->clock = NULL;
 488
 489        cpts_write32(cpts, 0, int_enable);
 490        cpts_write32(cpts, 0, control);
 491
 492        /* Drop all packet */
 493        skb_queue_purge(&cpts->txq);
 494
 495        clk_disable(cpts->refclk);
 496}
 497EXPORT_SYMBOL_GPL(cpts_unregister);
 498
 499static void cpts_calc_mult_shift(struct cpts *cpts)
 500{
 501        u64 frac, maxsec, ns;
 502        u32 freq;
 503
 504        freq = clk_get_rate(cpts->refclk);
 505
 506        /* Calc the maximum number of seconds which we can run before
 507         * wrapping around.
 508         */
 509        maxsec = cpts->cc.mask;
 510        do_div(maxsec, freq);
 511        /* limit conversation rate to 10 sec as higher values will produce
 512         * too small mult factors and so reduce the conversion accuracy
 513         */
 514        if (maxsec > 10)
 515                maxsec = 10;
 516
 517        /* Calc overflow check period (maxsec / 2) */
 518        cpts->ov_check_period = (HZ * maxsec) / 2;
 519        dev_info(cpts->dev, "cpts: overflow check period %lu (jiffies)\n",
 520                 cpts->ov_check_period);
 521
 522        if (cpts->cc.mult || cpts->cc.shift)
 523                return;
 524
 525        clocks_calc_mult_shift(&cpts->cc.mult, &cpts->cc.shift,
 526                               freq, NSEC_PER_SEC, maxsec);
 527
 528        frac = 0;
 529        ns = cyclecounter_cyc2ns(&cpts->cc, freq, cpts->cc.mask, &frac);
 530
 531        dev_info(cpts->dev,
 532                 "CPTS: ref_clk_freq:%u calc_mult:%u calc_shift:%u error:%lld nsec/sec\n",
 533                 freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
 534}
 535
 536static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
 537{
 538        struct device_node *refclk_np;
 539        const char **parent_names;
 540        unsigned int num_parents;
 541        struct clk_hw *clk_hw;
 542        int ret = -EINVAL;
 543        u32 *mux_table;
 544
 545        refclk_np = of_get_child_by_name(node, "cpts-refclk-mux");
 546        if (!refclk_np)
 547                /* refclk selection supported not for all SoCs */
 548                return 0;
 549
 550        num_parents = of_clk_get_parent_count(refclk_np);
 551        if (num_parents < 1) {
 552                dev_err(cpts->dev, "mux-clock %s must have parents\n",
 553                        refclk_np->name);
 554                goto mux_fail;
 555        }
 556
 557        parent_names = devm_kzalloc(cpts->dev, (sizeof(char *) * num_parents),
 558                                    GFP_KERNEL);
 559
 560        mux_table = devm_kzalloc(cpts->dev, sizeof(*mux_table) * num_parents,
 561                                 GFP_KERNEL);
 562        if (!mux_table || !parent_names) {
 563                ret = -ENOMEM;
 564                goto mux_fail;
 565        }
 566
 567        of_clk_parent_fill(refclk_np, parent_names, num_parents);
 568
 569        ret = of_property_read_variable_u32_array(refclk_np, "ti,mux-tbl",
 570                                                  mux_table,
 571                                                  num_parents, num_parents);
 572        if (ret < 0)
 573                goto mux_fail;
 574
 575        clk_hw = clk_hw_register_mux_table(cpts->dev, refclk_np->name,
 576                                           parent_names, num_parents,
 577                                           0,
 578                                           &cpts->reg->rftclk_sel, 0, 0x1F,
 579                                           0, mux_table, NULL);
 580        if (IS_ERR(clk_hw)) {
 581                ret = PTR_ERR(clk_hw);
 582                goto mux_fail;
 583        }
 584
 585        ret = devm_add_action_or_reset(cpts->dev,
 586                                       (void(*)(void *))clk_hw_unregister_mux,
 587                                       clk_hw);
 588        if (ret) {
 589                dev_err(cpts->dev, "add clkmux unreg action %d", ret);
 590                goto mux_fail;
 591        }
 592
 593        ret = of_clk_add_hw_provider(refclk_np, of_clk_hw_simple_get, clk_hw);
 594        if (ret)
 595                goto mux_fail;
 596
 597        ret = devm_add_action_or_reset(cpts->dev,
 598                                       (void(*)(void *))of_clk_del_provider,
 599                                       refclk_np);
 600        if (ret) {
 601                dev_err(cpts->dev, "add clkmux provider unreg action %d", ret);
 602                goto mux_fail;
 603        }
 604
 605        return ret;
 606
 607mux_fail:
 608        of_node_put(refclk_np);
 609        return ret;
 610}
 611
 612static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
 613{
 614        int ret = -EINVAL;
 615        u32 prop;
 616
 617        if (!of_property_read_u32(node, "cpts_clock_mult", &prop))
 618                cpts->cc.mult = prop;
 619
 620        if (!of_property_read_u32(node, "cpts_clock_shift", &prop))
 621                cpts->cc.shift = prop;
 622
 623        if ((cpts->cc.mult && !cpts->cc.shift) ||
 624            (!cpts->cc.mult && cpts->cc.shift))
 625                goto of_error;
 626
 627        return cpts_of_mux_clk_setup(cpts, node);
 628
 629of_error:
 630        dev_err(cpts->dev, "CPTS: Missing property in the DT.\n");
 631        return ret;
 632}
 633
 634struct cpts *cpts_create(struct device *dev, void __iomem *regs,
 635                         struct device_node *node)
 636{
 637        struct cpts *cpts;
 638        int ret;
 639
 640        cpts = devm_kzalloc(dev, sizeof(*cpts), GFP_KERNEL);
 641        if (!cpts)
 642                return ERR_PTR(-ENOMEM);
 643
 644        cpts->dev = dev;
 645        cpts->reg = (struct cpsw_cpts __iomem *)regs;
 646        spin_lock_init(&cpts->lock);
 647
 648        ret = cpts_of_parse(cpts, node);
 649        if (ret)
 650                return ERR_PTR(ret);
 651
 652        cpts->refclk = devm_get_clk_from_child(dev, node, "cpts");
 653        if (IS_ERR(cpts->refclk))
 654                /* try get clk from dev node for compatibility */
 655                cpts->refclk = devm_clk_get(dev, "cpts");
 656
 657        if (IS_ERR(cpts->refclk)) {
 658                dev_err(dev, "Failed to get cpts refclk %ld\n",
 659                        PTR_ERR(cpts->refclk));
 660                return ERR_CAST(cpts->refclk);
 661        }
 662
 663        ret = clk_prepare(cpts->refclk);
 664        if (ret)
 665                return ERR_PTR(ret);
 666
 667        cpts->cc.read = cpts_systim_read;
 668        cpts->cc.mask = CLOCKSOURCE_MASK(32);
 669        cpts->info = cpts_info;
 670
 671        cpts_calc_mult_shift(cpts);
 672        /* save cc.mult original value as it can be modified
 673         * by cpts_ptp_adjfreq().
 674         */
 675        cpts->cc_mult = cpts->cc.mult;
 676
 677        return cpts;
 678}
 679EXPORT_SYMBOL_GPL(cpts_create);
 680
 681void cpts_release(struct cpts *cpts)
 682{
 683        if (!cpts)
 684                return;
 685
 686        if (WARN_ON(!cpts->refclk))
 687                return;
 688
 689        clk_unprepare(cpts->refclk);
 690}
 691EXPORT_SYMBOL_GPL(cpts_release);
 692
 693MODULE_LICENSE("GPL v2");
 694MODULE_DESCRIPTION("TI CPTS driver");
 695MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
 696