brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 9667ce8 Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Synopsys AXS10X SDP I2S PLL clock driver4 *5 * Copyright (C) 2016 Synopsys6 */7 8#include <linux/platform_device.h>9#include <linux/module.h>10#include <linux/clk-provider.h>11#include <linux/err.h>12#include <linux/device.h>13#include <linux/io.h>14#include <linux/of_address.h>15#include <linux/slab.h>16#include <linux/of.h>17 18/* PLL registers addresses */19#define PLL_IDIV_REG	0x020#define PLL_FBDIV_REG	0x421#define PLL_ODIV0_REG	0x822#define PLL_ODIV1_REG	0xC23 24struct i2s_pll_cfg {25	unsigned int rate;26	unsigned int idiv;27	unsigned int fbdiv;28	unsigned int odiv0;29	unsigned int odiv1;30};31 32static const struct i2s_pll_cfg i2s_pll_cfg_27m[] = {33	/* 27 Mhz */34	{ 1024000, 0x104, 0x451, 0x10E38, 0x2000 },35	{ 1411200, 0x104, 0x596, 0x10D35, 0x2000 },36	{ 1536000, 0x208, 0xA28, 0x10B2C, 0x2000 },37	{ 2048000, 0x82, 0x451, 0x10E38, 0x2000 },38	{ 2822400, 0x82, 0x596, 0x10D35, 0x2000 },39	{ 3072000, 0x104, 0xA28, 0x10B2C, 0x2000 },40	{ 2116800, 0x82, 0x3CF, 0x10C30, 0x2000 },41	{ 2304000, 0x104, 0x79E, 0x10B2C, 0x2000 },42	{ 0, 0, 0, 0, 0 },43};44 45static const struct i2s_pll_cfg i2s_pll_cfg_28m[] = {46	/* 28.224 Mhz */47	{ 1024000, 0x82, 0x105, 0x107DF, 0x2000 },48	{ 1411200, 0x28A, 0x1, 0x10001, 0x2000 },49	{ 1536000, 0xA28, 0x187, 0x10042, 0x2000 },50	{ 2048000, 0x41, 0x105, 0x107DF, 0x2000 },51	{ 2822400, 0x145, 0x1, 0x10001, 0x2000 },52	{ 3072000, 0x514, 0x187, 0x10042, 0x2000 },53	{ 2116800, 0x514, 0x42, 0x10001, 0x2000 },54	{ 2304000, 0x619, 0x82, 0x10001, 0x2000 },55	{ 0, 0, 0, 0, 0 },56};57 58struct i2s_pll_clk {59	void __iomem *base;60	struct clk_hw hw;61	struct device *dev;62};63 64static inline void i2s_pll_write(struct i2s_pll_clk *clk, unsigned int reg,65		unsigned int val)66{67	writel_relaxed(val, clk->base + reg);68}69 70static inline unsigned int i2s_pll_read(struct i2s_pll_clk *clk,71		unsigned int reg)72{73	return readl_relaxed(clk->base + reg);74}75 76static inline struct i2s_pll_clk *to_i2s_pll_clk(struct clk_hw *hw)77{78	return container_of(hw, struct i2s_pll_clk, hw);79}80 81static inline unsigned int i2s_pll_get_value(unsigned int val)82{83	return (val & 0x3F) + ((val >> 6) & 0x3F);84}85 86static const struct i2s_pll_cfg *i2s_pll_get_cfg(unsigned long prate)87{88	switch (prate) {89	case 27000000:90		return i2s_pll_cfg_27m;91	case 28224000:92		return i2s_pll_cfg_28m;93	default:94		return NULL;95	}96}97 98static unsigned long i2s_pll_recalc_rate(struct clk_hw *hw,99			unsigned long parent_rate)100{101	struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);102	unsigned int idiv, fbdiv, odiv;103 104	idiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_IDIV_REG));105	fbdiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_FBDIV_REG));106	odiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_ODIV0_REG));107 108	return ((parent_rate / idiv) * fbdiv) / odiv;109}110 111static long i2s_pll_round_rate(struct clk_hw *hw, unsigned long rate,112			unsigned long *prate)113{114	struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);115	const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(*prate);116	int i;117 118	if (!pll_cfg) {119		dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);120		return -EINVAL;121	}122 123	for (i = 0; pll_cfg[i].rate != 0; i++)124		if (pll_cfg[i].rate == rate)125			return rate;126 127	return -EINVAL;128}129 130static int i2s_pll_set_rate(struct clk_hw *hw, unsigned long rate,131			unsigned long parent_rate)132{133	struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);134	const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(parent_rate);135	int i;136 137	if (!pll_cfg) {138		dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate);139		return -EINVAL;140	}141 142	for (i = 0; pll_cfg[i].rate != 0; i++) {143		if (pll_cfg[i].rate == rate) {144			i2s_pll_write(clk, PLL_IDIV_REG, pll_cfg[i].idiv);145			i2s_pll_write(clk, PLL_FBDIV_REG, pll_cfg[i].fbdiv);146			i2s_pll_write(clk, PLL_ODIV0_REG, pll_cfg[i].odiv0);147			i2s_pll_write(clk, PLL_ODIV1_REG, pll_cfg[i].odiv1);148			return 0;149		}150	}151 152	dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,153			parent_rate);154	return -EINVAL;155}156 157static const struct clk_ops i2s_pll_ops = {158	.recalc_rate = i2s_pll_recalc_rate,159	.round_rate = i2s_pll_round_rate,160	.set_rate = i2s_pll_set_rate,161};162 163static int i2s_pll_clk_probe(struct platform_device *pdev)164{165	struct device *dev = &pdev->dev;166	struct device_node *node = dev->of_node;167	const char *clk_name;168	const char *parent_name;169	struct clk *clk;170	struct i2s_pll_clk *pll_clk;171	struct clk_init_data init;172 173	pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);174	if (!pll_clk)175		return -ENOMEM;176 177	pll_clk->base = devm_platform_ioremap_resource(pdev, 0);178	if (IS_ERR(pll_clk->base))179		return PTR_ERR(pll_clk->base);180 181	memset(&init, 0, sizeof(init));182	clk_name = node->name;183	init.name = clk_name;184	init.ops = &i2s_pll_ops;185	parent_name = of_clk_get_parent_name(node, 0);186	init.parent_names = &parent_name;187	init.num_parents = 1;188	pll_clk->hw.init = &init;189	pll_clk->dev = dev;190 191	clk = devm_clk_register(dev, &pll_clk->hw);192	if (IS_ERR(clk)) {193		dev_err(dev, "failed to register %s clock (%ld)\n",194				clk_name, PTR_ERR(clk));195		return PTR_ERR(clk);196	}197 198	return of_clk_add_provider(node, of_clk_src_simple_get, clk);199}200 201static void i2s_pll_clk_remove(struct platform_device *pdev)202{203	of_clk_del_provider(pdev->dev.of_node);204}205 206static const struct of_device_id i2s_pll_clk_id[] = {207	{ .compatible = "snps,axs10x-i2s-pll-clock", },208	{ },209};210MODULE_DEVICE_TABLE(of, i2s_pll_clk_id);211 212static struct platform_driver i2s_pll_clk_driver = {213	.driver = {214		.name = "axs10x-i2s-pll-clock",215		.of_match_table = i2s_pll_clk_id,216	},217	.probe = i2s_pll_clk_probe,218	.remove = i2s_pll_clk_remove,219};220module_platform_driver(i2s_pll_clk_driver);221 222MODULE_AUTHOR("Jose Abreu <joabreu@synopsys.com>");223MODULE_DESCRIPTION("Synopsys AXS10X SDP I2S PLL Clock Driver");224MODULE_LICENSE("GPL v2");225