brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · cbd17a5 Raw
160 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Amlogic Meson SDHC clock controller4 *5 * Copyright (C) 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>6 */7 8#include <linux/clk.h>9#include <linux/clk-provider.h>10#include <linux/device.h>11#include <linux/platform_device.h>12 13#include "meson-mx-sdhc.h"14 15struct meson_mx_sdhc_clkc {16	struct clk_mux			src_sel;17	struct clk_divider		div;18	struct clk_gate			mod_clk_en;19	struct clk_gate			tx_clk_en;20	struct clk_gate			rx_clk_en;21	struct clk_gate			sd_clk_en;22};23 24static const struct clk_parent_data meson_mx_sdhc_src_sel_parents[4] = {25	{ .fw_name = "clkin0" },26	{ .fw_name = "clkin1" },27	{ .fw_name = "clkin2" },28	{ .fw_name = "clkin3" },29};30 31static const struct clk_div_table meson_mx_sdhc_div_table[] = {32	{ .div = 6, .val = 5, },33	{ .div = 8, .val = 7, },34	{ .div = 9, .val = 8, },35	{ .div = 10, .val = 9, },36	{ .div = 12, .val = 11, },37	{ .div = 16, .val = 15, },38	{ .div = 18, .val = 17, },39	{ .div = 34, .val = 33, },40	{ .div = 142, .val = 141, },41	{ .div = 850, .val = 849, },42	{ .div = 2126, .val = 2125, },43	{ .div = 4096, .val = 4095, },44	{ /* sentinel */ }45};46 47static int meson_mx_sdhc_clk_hw_register(struct device *dev,48					 const char *name_suffix,49					 const struct clk_parent_data *parents,50					 unsigned int num_parents,51					 const struct clk_ops *ops,52					 struct clk_hw *hw)53{54	struct clk_init_data init = { };55	char clk_name[32];56 57	snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dev),58		 name_suffix);59 60	init.name = clk_name;61	init.ops = ops;62	init.flags = CLK_SET_RATE_PARENT;63	init.parent_data = parents;64	init.num_parents = num_parents;65 66	hw->init = &init;67 68	return devm_clk_hw_register(dev, hw);69}70 71static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev,72					      const char *name_suffix,73					      struct clk_hw *parent,74					      struct clk_hw *hw,75					      struct clk_bulk_data *clk_bulk_data,76					      u8 bulk_index)77{78	struct clk_parent_data parent_data = { .hw = parent };79	int ret;80 81	ret = meson_mx_sdhc_clk_hw_register(dev, name_suffix, &parent_data, 1,82					    &clk_gate_ops, hw);83	if (ret)84		return ret;85 86	clk_bulk_data[bulk_index].clk = devm_clk_hw_get_clk(dev, hw, name_suffix);87	if (IS_ERR(clk_bulk_data[bulk_index].clk))88		return PTR_ERR(clk_bulk_data[bulk_index].clk);89 90	return 0;91}92 93int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,94				struct clk_bulk_data *clk_bulk_data)95{96	struct clk_parent_data div_parent = { };97	struct meson_mx_sdhc_clkc *clkc_data;98	int ret;99 100	clkc_data = devm_kzalloc(dev, sizeof(*clkc_data), GFP_KERNEL);101	if (!clkc_data)102		return -ENOMEM;103 104	clkc_data->src_sel.reg = base + MESON_SDHC_CLKC;105	clkc_data->src_sel.mask = 0x3;106	clkc_data->src_sel.shift = 16;107	ret = meson_mx_sdhc_clk_hw_register(dev, "src_sel",108					    meson_mx_sdhc_src_sel_parents, 4,109					    &clk_mux_ops,110					    &clkc_data->src_sel.hw);111	if (ret)112		return ret;113 114	clkc_data->div.reg = base + MESON_SDHC_CLKC;115	clkc_data->div.shift = 0;116	clkc_data->div.width = 12;117	clkc_data->div.table = meson_mx_sdhc_div_table;118	div_parent.hw = &clkc_data->src_sel.hw;119	ret = meson_mx_sdhc_clk_hw_register(dev, "div", &div_parent, 1,120					    &clk_divider_ops,121					    &clkc_data->div.hw);122	if (ret)123		return ret;124 125	clkc_data->mod_clk_en.reg = base + MESON_SDHC_CLKC;126	clkc_data->mod_clk_en.bit_idx = 15;127	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "mod_clk_on",128						 &clkc_data->div.hw,129						 &clkc_data->mod_clk_en.hw,130						 clk_bulk_data, 0);131	if (ret)132		return ret;133 134	clkc_data->tx_clk_en.reg = base + MESON_SDHC_CLKC;135	clkc_data->tx_clk_en.bit_idx = 14;136	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "tx_clk_on",137						 &clkc_data->div.hw,138						 &clkc_data->tx_clk_en.hw,139						 clk_bulk_data, 1);140	if (ret)141		return ret;142 143	clkc_data->rx_clk_en.reg = base + MESON_SDHC_CLKC;144	clkc_data->rx_clk_en.bit_idx = 13;145	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "rx_clk_on",146						 &clkc_data->div.hw,147						 &clkc_data->rx_clk_en.hw,148						 clk_bulk_data, 2);149	if (ret)150		return ret;151 152	clkc_data->sd_clk_en.reg = base + MESON_SDHC_CLKC;153	clkc_data->sd_clk_en.bit_idx = 12;154	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "sd_clk_on",155						 &clkc_data->div.hw,156						 &clkc_data->sd_clk_en.hw,157						 clk_bulk_data, 3);158	return ret;159}160