linux/drivers/clk/mediatek/clk-apmixed.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 MediaTek Inc.
   3 * Author: James Liao <jamesjj.liao@mediatek.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 */
  14
  15#include <linux/delay.h>
  16#include <linux/of_address.h>
  17#include <linux/slab.h>
  18
  19#include "clk-mtk.h"
  20
  21#define REF2USB_TX_EN           BIT(0)
  22#define REF2USB_TX_LPF_EN       BIT(1)
  23#define REF2USB_TX_OUT_EN       BIT(2)
  24#define REF2USB_EN_MASK         (REF2USB_TX_EN | REF2USB_TX_LPF_EN | \
  25                                 REF2USB_TX_OUT_EN)
  26
  27struct mtk_ref2usb_tx {
  28        struct clk_hw   hw;
  29        void __iomem    *base_addr;
  30};
  31
  32static inline struct mtk_ref2usb_tx *to_mtk_ref2usb_tx(struct clk_hw *hw)
  33{
  34        return container_of(hw, struct mtk_ref2usb_tx, hw);
  35}
  36
  37static int mtk_ref2usb_tx_is_prepared(struct clk_hw *hw)
  38{
  39        struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
  40
  41        return (readl(tx->base_addr) & REF2USB_EN_MASK) == REF2USB_EN_MASK;
  42}
  43
  44static int mtk_ref2usb_tx_prepare(struct clk_hw *hw)
  45{
  46        struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
  47        u32 val;
  48
  49        val = readl(tx->base_addr);
  50
  51        val |= REF2USB_TX_EN;
  52        writel(val, tx->base_addr);
  53        udelay(100);
  54
  55        val |= REF2USB_TX_LPF_EN;
  56        writel(val, tx->base_addr);
  57
  58        val |= REF2USB_TX_OUT_EN;
  59        writel(val, tx->base_addr);
  60
  61        return 0;
  62}
  63
  64static void mtk_ref2usb_tx_unprepare(struct clk_hw *hw)
  65{
  66        struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
  67        u32 val;
  68
  69        val = readl(tx->base_addr);
  70        val &= ~REF2USB_EN_MASK;
  71        writel(val, tx->base_addr);
  72}
  73
  74static const struct clk_ops mtk_ref2usb_tx_ops = {
  75        .is_prepared    = mtk_ref2usb_tx_is_prepared,
  76        .prepare        = mtk_ref2usb_tx_prepare,
  77        .unprepare      = mtk_ref2usb_tx_unprepare,
  78};
  79
  80struct clk * __init mtk_clk_register_ref2usb_tx(const char *name,
  81                        const char *parent_name, void __iomem *reg)
  82{
  83        struct mtk_ref2usb_tx *tx;
  84        struct clk_init_data init = {};
  85        struct clk *clk;
  86
  87        tx = kzalloc(sizeof(*tx), GFP_KERNEL);
  88        if (!tx)
  89                return ERR_PTR(-ENOMEM);
  90
  91        tx->base_addr = reg;
  92        tx->hw.init = &init;
  93
  94        init.name = name;
  95        init.ops = &mtk_ref2usb_tx_ops;
  96        init.parent_names = &parent_name;
  97        init.num_parents = 1;
  98
  99        clk = clk_register(NULL, &tx->hw);
 100
 101        if (IS_ERR(clk)) {
 102                pr_err("Failed to register clk %s: %ld\n", name, PTR_ERR(clk));
 103                kfree(tx);
 104        }
 105
 106        return clk;
 107}
 108