Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * R-Car Gen3 Clock Pulse Generator Library
0004  *
0005  * Copyright (C) 2015-2018 Glider bvba
0006  * Copyright (C) 2019 Renesas Electronics Corp.
0007  *
0008  * Based on clk-rcar-gen3.c
0009  *
0010  * Copyright (C) 2015 Renesas Electronics Corp.
0011  */
0012 
0013 #include <linux/clk.h>
0014 #include <linux/clk-provider.h>
0015 #include <linux/device.h>
0016 #include <linux/err.h>
0017 #include <linux/init.h>
0018 #include <linux/io.h>
0019 #include <linux/pm.h>
0020 #include <linux/slab.h>
0021 #include <linux/sys_soc.h>
0022 
0023 #include "rcar-cpg-lib.h"
0024 
0025 spinlock_t cpg_lock;
0026 
0027 void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set)
0028 {
0029     unsigned long flags;
0030     u32 val;
0031 
0032     spin_lock_irqsave(&cpg_lock, flags);
0033     val = readl(reg);
0034     val &= ~clear;
0035     val |= set;
0036     writel(val, reg);
0037     spin_unlock_irqrestore(&cpg_lock, flags);
0038 };
0039 
0040 static int cpg_simple_notifier_call(struct notifier_block *nb,
0041                     unsigned long action, void *data)
0042 {
0043     struct cpg_simple_notifier *csn =
0044         container_of(nb, struct cpg_simple_notifier, nb);
0045 
0046     switch (action) {
0047     case PM_EVENT_SUSPEND:
0048         csn->saved = readl(csn->reg);
0049         return NOTIFY_OK;
0050 
0051     case PM_EVENT_RESUME:
0052         writel(csn->saved, csn->reg);
0053         return NOTIFY_OK;
0054     }
0055     return NOTIFY_DONE;
0056 }
0057 
0058 void cpg_simple_notifier_register(struct raw_notifier_head *notifiers,
0059                   struct cpg_simple_notifier *csn)
0060 {
0061     csn->nb.notifier_call = cpg_simple_notifier_call;
0062     raw_notifier_chain_register(notifiers, &csn->nb);
0063 }
0064 
0065 /*
0066  * SDn Clock
0067  */
0068 
0069 #define SDnSRCFC_SHIFT 2
0070 #define STPnHCK BIT(9 - SDnSRCFC_SHIFT)
0071 
0072 static const struct clk_div_table cpg_sdh_div_table[] = {
0073     { 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 },
0074     { STPnHCK | 4, 16 }, { 0, 0 },
0075 };
0076 
0077 struct clk * __init cpg_sdh_clk_register(const char *name,
0078     void __iomem *sdnckcr, const char *parent_name,
0079     struct raw_notifier_head *notifiers)
0080 {
0081     struct cpg_simple_notifier *csn;
0082     struct clk *clk;
0083 
0084     csn = kzalloc(sizeof(*csn), GFP_KERNEL);
0085     if (!csn)
0086         return ERR_PTR(-ENOMEM);
0087 
0088     csn->reg = sdnckcr;
0089 
0090     clk = clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr,
0091                      SDnSRCFC_SHIFT, 8, 0, cpg_sdh_div_table,
0092                      &cpg_lock);
0093     if (IS_ERR(clk)) {
0094         kfree(csn);
0095         return clk;
0096     }
0097 
0098     cpg_simple_notifier_register(notifiers, csn);
0099     return clk;
0100 }
0101 
0102 static const struct clk_div_table cpg_sd_div_table[] = {
0103     { 0, 2 }, { 1, 4 }, { 0, 0 },
0104 };
0105 
0106 struct clk * __init cpg_sd_clk_register(const char *name,
0107     void __iomem *sdnckcr, const char *parent_name)
0108 {
0109     return clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr,
0110                       0, 2, 0, cpg_sd_div_table, &cpg_lock);
0111 }
0112 
0113 struct rpc_clock {
0114     struct clk_divider div;
0115     struct clk_gate gate;
0116     /*
0117      * One notifier covers both RPC and RPCD2 clocks as they are both
0118      * controlled by the same RPCCKCR register...
0119      */
0120     struct cpg_simple_notifier csn;
0121 };
0122 
0123 static const struct clk_div_table cpg_rpc_div_table[] = {
0124     { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 },
0125 };
0126 
0127 struct clk * __init cpg_rpc_clk_register(const char *name,
0128     void __iomem *rpcckcr, const char *parent_name,
0129     struct raw_notifier_head *notifiers)
0130 {
0131     struct rpc_clock *rpc;
0132     struct clk *clk;
0133 
0134     rpc = kzalloc(sizeof(*rpc), GFP_KERNEL);
0135     if (!rpc)
0136         return ERR_PTR(-ENOMEM);
0137 
0138     rpc->div.reg = rpcckcr;
0139     rpc->div.width = 3;
0140     rpc->div.table = cpg_rpc_div_table;
0141     rpc->div.lock = &cpg_lock;
0142 
0143     rpc->gate.reg = rpcckcr;
0144     rpc->gate.bit_idx = 8;
0145     rpc->gate.flags = CLK_GATE_SET_TO_DISABLE;
0146     rpc->gate.lock = &cpg_lock;
0147 
0148     rpc->csn.reg = rpcckcr;
0149 
0150     clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
0151                      &rpc->div.hw,  &clk_divider_ops,
0152                      &rpc->gate.hw, &clk_gate_ops,
0153                      CLK_SET_RATE_PARENT);
0154     if (IS_ERR(clk)) {
0155         kfree(rpc);
0156         return clk;
0157     }
0158 
0159     cpg_simple_notifier_register(notifiers, &rpc->csn);
0160     return clk;
0161 }
0162 
0163 struct rpcd2_clock {
0164     struct clk_fixed_factor fixed;
0165     struct clk_gate gate;
0166 };
0167 
0168 struct clk * __init cpg_rpcd2_clk_register(const char *name,
0169                        void __iomem *rpcckcr,
0170                        const char *parent_name)
0171 {
0172     struct rpcd2_clock *rpcd2;
0173     struct clk *clk;
0174 
0175     rpcd2 = kzalloc(sizeof(*rpcd2), GFP_KERNEL);
0176     if (!rpcd2)
0177         return ERR_PTR(-ENOMEM);
0178 
0179     rpcd2->fixed.mult = 1;
0180     rpcd2->fixed.div = 2;
0181 
0182     rpcd2->gate.reg = rpcckcr;
0183     rpcd2->gate.bit_idx = 9;
0184     rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE;
0185     rpcd2->gate.lock = &cpg_lock;
0186 
0187     clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
0188                      &rpcd2->fixed.hw, &clk_fixed_factor_ops,
0189                      &rpcd2->gate.hw, &clk_gate_ops,
0190                      CLK_SET_RATE_PARENT);
0191     if (IS_ERR(clk))
0192         kfree(rpcd2);
0193 
0194     return clk;
0195 }
0196