Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: Add Oxford Semiconductor OXNAS Standard Clocks

Add Oxford Semiconductor OXNAS SoC Family Standard Clocks support.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
[sboyd@codeaurora.org: Drop NULL/continue check in registration
loop]
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Neil Armstrong and committed by
Stephen Boyd
0bbd72b4 bb4399b8

+202
+6
drivers/clk/Kconfig
··· 197 197 ---help--- 198 198 Support for the Marvell PXA SoC. 199 199 200 + config COMMON_CLK_OXNAS 201 + bool "Clock driver for the OXNAS SoC Family" 202 + select MFD_SYSCON 203 + ---help--- 204 + Support for the OXNAS SoC Family clocks. 205 + 200 206 source "drivers/clk/bcm/Kconfig" 201 207 source "drivers/clk/hisilicon/Kconfig" 202 208 source "drivers/clk/mvebu/Kconfig"
+1
drivers/clk/Makefile
··· 33 33 obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o 34 34 obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o 35 35 obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o 36 + obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o 36 37 obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o 37 38 obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o 38 39 obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
+195
drivers/clk/clk-oxnas.c
··· 1 + /* 2 + * Copyright (C) 2010 Broadcom 3 + * Copyright (C) 2012 Stephen Warren 4 + * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + 19 + #include <linux/clk-provider.h> 20 + #include <linux/kernel.h> 21 + #include <linux/module.h> 22 + #include <linux/of.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/stringify.h> 25 + #include <linux/regmap.h> 26 + #include <linux/mfd/syscon.h> 27 + 28 + /* Standard regmap gate clocks */ 29 + struct clk_oxnas { 30 + struct clk_hw hw; 31 + signed char bit; 32 + struct regmap *regmap; 33 + }; 34 + 35 + /* Regmap offsets */ 36 + #define CLK_STAT_REGOFFSET 0x24 37 + #define CLK_SET_REGOFFSET 0x2c 38 + #define CLK_CLR_REGOFFSET 0x30 39 + 40 + static inline struct clk_oxnas *to_clk_oxnas(struct clk_hw *hw) 41 + { 42 + return container_of(hw, struct clk_oxnas, hw); 43 + } 44 + 45 + static int oxnas_clk_is_enabled(struct clk_hw *hw) 46 + { 47 + struct clk_oxnas *std = to_clk_oxnas(hw); 48 + int ret; 49 + unsigned int val; 50 + 51 + ret = regmap_read(std->regmap, CLK_STAT_REGOFFSET, &val); 52 + if (ret < 0) 53 + return ret; 54 + 55 + return val & BIT(std->bit); 56 + } 57 + 58 + static int oxnas_clk_enable(struct clk_hw *hw) 59 + { 60 + struct clk_oxnas *std = to_clk_oxnas(hw); 61 + 62 + regmap_write(std->regmap, CLK_SET_REGOFFSET, BIT(std->bit)); 63 + 64 + return 0; 65 + } 66 + 67 + static void oxnas_clk_disable(struct clk_hw *hw) 68 + { 69 + struct clk_oxnas *std = to_clk_oxnas(hw); 70 + 71 + regmap_write(std->regmap, CLK_CLR_REGOFFSET, BIT(std->bit)); 72 + } 73 + 74 + static const struct clk_ops oxnas_clk_ops = { 75 + .enable = oxnas_clk_enable, 76 + .disable = oxnas_clk_disable, 77 + .is_enabled = oxnas_clk_is_enabled, 78 + }; 79 + 80 + static const char *const oxnas_clk_parents[] = { 81 + "oscillator", 82 + }; 83 + 84 + static const char *const eth_parents[] = { 85 + "gmacclk", 86 + }; 87 + 88 + #define DECLARE_STD_CLKP(__clk, __parent) \ 89 + static const struct clk_init_data clk_##__clk##_init = { \ 90 + .name = __stringify(__clk), \ 91 + .ops = &oxnas_clk_ops, \ 92 + .parent_names = __parent, \ 93 + .num_parents = ARRAY_SIZE(__parent), \ 94 + } 95 + 96 + #define DECLARE_STD_CLK(__clk) DECLARE_STD_CLKP(__clk, oxnas_clk_parents) 97 + 98 + /* Hardware Bit - Clock association */ 99 + struct clk_oxnas_init_data { 100 + unsigned long bit; 101 + const struct clk_init_data *clk_init; 102 + }; 103 + 104 + /* Clk init data declaration */ 105 + DECLARE_STD_CLK(leon); 106 + DECLARE_STD_CLK(dma_sgdma); 107 + DECLARE_STD_CLK(cipher); 108 + DECLARE_STD_CLK(sata); 109 + DECLARE_STD_CLK(audio); 110 + DECLARE_STD_CLK(usbmph); 111 + DECLARE_STD_CLKP(etha, eth_parents); 112 + DECLARE_STD_CLK(pciea); 113 + DECLARE_STD_CLK(nand); 114 + 115 + /* Table index is clock indice */ 116 + static const struct clk_oxnas_init_data clk_oxnas_init[] = { 117 + [0] = {0, &clk_leon_init}, 118 + [1] = {1, &clk_dma_sgdma_init}, 119 + [2] = {2, &clk_cipher_init}, 120 + /* Skip & Do not touch to DDR clock */ 121 + [3] = {4, &clk_sata_init}, 122 + [4] = {5, &clk_audio_init}, 123 + [5] = {6, &clk_usbmph_init}, 124 + [6] = {7, &clk_etha_init}, 125 + [7] = {8, &clk_pciea_init}, 126 + [8] = {9, &clk_nand_init}, 127 + }; 128 + 129 + struct clk_oxnas_data { 130 + struct clk_oxnas clk_oxnas[ARRAY_SIZE(clk_oxnas_init)]; 131 + struct clk_onecell_data onecell_data[ARRAY_SIZE(clk_oxnas_init)]; 132 + struct clk *clks[ARRAY_SIZE(clk_oxnas_init)]; 133 + }; 134 + 135 + static int oxnas_stdclk_probe(struct platform_device *pdev) 136 + { 137 + struct device_node *np = pdev->dev.of_node; 138 + struct clk_oxnas_data *clk_oxnas; 139 + struct regmap *regmap; 140 + int i; 141 + 142 + clk_oxnas = devm_kzalloc(&pdev->dev, sizeof(*clk_oxnas), GFP_KERNEL); 143 + if (!clk_oxnas) 144 + return -ENOMEM; 145 + 146 + regmap = syscon_node_to_regmap(of_get_parent(np)); 147 + if (!regmap) { 148 + dev_err(&pdev->dev, "failed to have parent regmap\n"); 149 + return -EINVAL; 150 + } 151 + 152 + for (i = 0; i < ARRAY_SIZE(clk_oxnas_init); i++) { 153 + struct clk_oxnas *_clk; 154 + 155 + _clk = &clk_oxnas->clk_oxnas[i]; 156 + _clk->bit = clk_oxnas_init[i].bit; 157 + _clk->hw.init = clk_oxnas_init[i].clk_init; 158 + _clk->regmap = regmap; 159 + 160 + clk_oxnas->clks[i] = 161 + devm_clk_register(&pdev->dev, &_clk->hw); 162 + if (WARN_ON(IS_ERR(clk_oxnas->clks[i]))) 163 + return PTR_ERR(clk_oxnas->clks[i]); 164 + } 165 + 166 + clk_oxnas->onecell_data->clks = clk_oxnas->clks; 167 + clk_oxnas->onecell_data->clk_num = ARRAY_SIZE(clk_oxnas_init); 168 + 169 + return of_clk_add_provider(np, of_clk_src_onecell_get, 170 + clk_oxnas->onecell_data); 171 + } 172 + 173 + static int oxnas_stdclk_remove(struct platform_device *pdev) 174 + { 175 + of_clk_del_provider(pdev->dev.of_node); 176 + 177 + return 0; 178 + } 179 + 180 + static const struct of_device_id oxnas_stdclk_dt_ids[] = { 181 + { .compatible = "oxsemi,ox810se-stdclk" }, 182 + { } 183 + }; 184 + MODULE_DEVICE_TABLE(of, oxnas_stdclk_dt_ids); 185 + 186 + static struct platform_driver oxnas_stdclk_driver = { 187 + .probe = oxnas_stdclk_probe, 188 + .remove = oxnas_stdclk_remove, 189 + .driver = { 190 + .name = "oxnas-stdclk", 191 + .of_match_table = oxnas_stdclk_dt_ids, 192 + }, 193 + }; 194 + 195 + module_platform_driver(oxnas_stdclk_driver);