brintos

brintos / linux-shallow public Read only

0
0
Text · 17.1 KiB · 18c20af Raw
661 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2018 Socionext Inc.4 * Copyright (C) 2016 Linaro Ltd.5 */6 7#include <linux/clk-provider.h>8#include <linux/err.h>9#include <linux/io.h>10#include <linux/iopoll.h>11#include <linux/of_address.h>12#include <linux/platform_device.h>13#include <linux/slab.h>14#include <linux/spinlock.h>15 16#define M10V_CLKSEL1		0x017#define CLKSEL(n)	(((n) - 1) * 4 + M10V_CLKSEL1)18 19#define M10V_PLL1		"pll1"20#define M10V_PLL1DIV2		"pll1-2"21#define M10V_PLL2		"pll2"22#define M10V_PLL2DIV2		"pll2-2"23#define M10V_PLL6		"pll6"24#define M10V_PLL6DIV2		"pll6-2"25#define M10V_PLL6DIV3		"pll6-3"26#define M10V_PLL7		"pll7"27#define M10V_PLL7DIV2		"pll7-2"28#define M10V_PLL7DIV5		"pll7-5"29#define M10V_PLL9		"pll9"30#define M10V_PLL10		"pll10"31#define M10V_PLL10DIV2		"pll10-2"32#define M10V_PLL11		"pll11"33 34#define M10V_SPI_PARENT0	"spi-parent0"35#define M10V_SPI_PARENT1	"spi-parent1"36#define M10V_SPI_PARENT2	"spi-parent2"37#define M10V_UHS1CLK2_PARENT0	"uhs1clk2-parent0"38#define M10V_UHS1CLK2_PARENT1	"uhs1clk2-parent1"39#define M10V_UHS1CLK2_PARENT2	"uhs1clk2-parent2"40#define M10V_UHS1CLK1_PARENT0	"uhs1clk1-parent0"41#define M10V_UHS1CLK1_PARENT1	"uhs1clk1-parent1"42#define M10V_NFCLK_PARENT0	"nfclk-parent0"43#define M10V_NFCLK_PARENT1	"nfclk-parent1"44#define M10V_NFCLK_PARENT2	"nfclk-parent2"45#define M10V_NFCLK_PARENT3	"nfclk-parent3"46#define M10V_NFCLK_PARENT4	"nfclk-parent4"47#define M10V_NFCLK_PARENT5	"nfclk-parent5"48 49#define M10V_DCHREQ		150#define M10V_UPOLL_RATE		151#define M10V_UTIMEOUT		25052 53#define M10V_EMMCCLK_ID		054#define M10V_ACLK_ID		155#define M10V_HCLK_ID		256#define M10V_PCLK_ID		357#define M10V_RCLK_ID		458#define M10V_SPICLK_ID		559#define M10V_NFCLK_ID		660#define M10V_UHS1CLK2_ID	761#define M10V_NUM_CLKS		862 63#define to_m10v_div(_hw)        container_of(_hw, struct m10v_clk_divider, hw)64 65static struct clk_hw_onecell_data *m10v_clk_data;66 67static DEFINE_SPINLOCK(m10v_crglock);68 69struct m10v_clk_div_factors {70	const char			*name;71	const char			*parent_name;72	u32				offset;73	u8				shift;74	u8				width;75	const struct clk_div_table	*table;76	unsigned long			div_flags;77	int				onecell_idx;78};79 80struct m10v_clk_div_fixed_data {81	const char	*name;82	const char	*parent_name;83	u8		div;84	u8		mult;85	int		onecell_idx;86};87 88struct m10v_clk_mux_factors {89	const char		*name;90	const char * const	*parent_names;91	u8			num_parents;92	u32			offset;93	u8			shift;94	u8			mask;95	u32			*table;96	unsigned long		mux_flags;97	int			onecell_idx;98};99 100static const struct clk_div_table emmcclk_table[] = {101	{ .val = 0, .div = 8 },102	{ .val = 1, .div = 9 },103	{ .val = 2, .div = 10 },104	{ .val = 3, .div = 15 },105	{ .div = 0 },106};107 108static const struct clk_div_table mclk400_table[] = {109	{ .val = 1, .div = 2 },110	{ .val = 3, .div = 4 },111	{ .div = 0 },112};113 114static const struct clk_div_table mclk200_table[] = {115	{ .val = 3, .div = 4 },116	{ .val = 7, .div = 8 },117	{ .div = 0 },118};119 120static const struct clk_div_table aclk400_table[] = {121	{ .val = 1, .div = 2 },122	{ .val = 3, .div = 4 },123	{ .div = 0 },124};125 126static const struct clk_div_table aclk300_table[] = {127	{ .val = 0, .div = 2 },128	{ .val = 1, .div = 3 },129	{ .div = 0 },130};131 132static const struct clk_div_table aclk_table[] = {133	{ .val = 3, .div = 4 },134	{ .val = 7, .div = 8 },135	{ .div = 0 },136};137 138static const struct clk_div_table aclkexs_table[] = {139	{ .val = 3, .div = 4 },140	{ .val = 4, .div = 5 },141	{ .val = 5, .div = 6 },142	{ .val = 7, .div = 8 },143	{ .div = 0 },144};145 146static const struct clk_div_table hclk_table[] = {147	{ .val = 7, .div = 8 },148	{ .val = 15, .div = 16 },149	{ .div = 0 },150};151 152static const struct clk_div_table hclkbmh_table[] = {153	{ .val = 3, .div = 4 },154	{ .val = 7, .div = 8 },155	{ .div = 0 },156};157 158static const struct clk_div_table pclk_table[] = {159	{ .val = 15, .div = 16 },160	{ .val = 31, .div = 32 },161	{ .div = 0 },162};163 164static const struct clk_div_table rclk_table[] = {165	{ .val = 0, .div = 8 },166	{ .val = 1, .div = 16 },167	{ .val = 2, .div = 24 },168	{ .val = 3, .div = 32 },169	{ .div = 0 },170};171 172static const struct clk_div_table uhs1clk0_table[] = {173	{ .val = 0, .div = 2 },174	{ .val = 1, .div = 3 },175	{ .val = 2, .div = 4 },176	{ .val = 3, .div = 8 },177	{ .val = 4, .div = 16 },178	{ .div = 0 },179};180 181static const struct clk_div_table uhs2clk_table[] = {182	{ .val = 0, .div = 9 },183	{ .val = 1, .div = 10 },184	{ .val = 2, .div = 11 },185	{ .val = 3, .div = 12 },186	{ .val = 4, .div = 13 },187	{ .val = 5, .div = 14 },188	{ .val = 6, .div = 16 },189	{ .val = 7, .div = 18 },190	{ .div = 0 },191};192 193static u32 spi_mux_table[] = {0, 1, 2};194static const char * const spi_mux_names[] = {195	M10V_SPI_PARENT0, M10V_SPI_PARENT1, M10V_SPI_PARENT2196};197 198static u32 uhs1clk2_mux_table[] = {2, 3, 4, 8};199static const char * const uhs1clk2_mux_names[] = {200	M10V_UHS1CLK2_PARENT0, M10V_UHS1CLK2_PARENT1,201	M10V_UHS1CLK2_PARENT2, M10V_PLL6DIV2202};203 204static u32 uhs1clk1_mux_table[] = {3, 4, 8};205static const char * const uhs1clk1_mux_names[] = {206	M10V_UHS1CLK1_PARENT0, M10V_UHS1CLK1_PARENT1, M10V_PLL6DIV2207};208 209static u32 nfclk_mux_table[] = {0, 1, 2, 3, 4, 8};210static const char * const nfclk_mux_names[] = {211	M10V_NFCLK_PARENT0, M10V_NFCLK_PARENT1, M10V_NFCLK_PARENT2,212	M10V_NFCLK_PARENT3, M10V_NFCLK_PARENT4, M10V_NFCLK_PARENT5213};214 215static const struct m10v_clk_div_fixed_data m10v_pll_fixed_data[] = {216	{M10V_PLL1, NULL, 1, 40, -1},217	{M10V_PLL2, NULL, 1, 30, -1},218	{M10V_PLL6, NULL, 1, 35, -1},219	{M10V_PLL7, NULL, 1, 40, -1},220	{M10V_PLL9, NULL, 1, 33, -1},221	{M10V_PLL10, NULL, 5, 108, -1},222	{M10V_PLL10DIV2, M10V_PLL10, 2, 1, -1},223	{M10V_PLL11, NULL, 2, 75, -1},224};225 226static const struct m10v_clk_div_fixed_data m10v_div_fixed_data[] = {227	{"usb2", NULL, 2, 1, -1},228	{"pcisuppclk", NULL, 20, 1, -1},229	{M10V_PLL1DIV2, M10V_PLL1, 2, 1, -1},230	{M10V_PLL2DIV2, M10V_PLL2, 2, 1, -1},231	{M10V_PLL6DIV2, M10V_PLL6, 2, 1, -1},232	{M10V_PLL6DIV3, M10V_PLL6, 3, 1, -1},233	{M10V_PLL7DIV2, M10V_PLL7, 2, 1, -1},234	{M10V_PLL7DIV5, M10V_PLL7, 5, 1, -1},235	{"ca7wd", M10V_PLL2DIV2, 12, 1, -1},236	{"pclkca7wd", M10V_PLL1DIV2, 16, 1, -1},237	{M10V_SPI_PARENT0, M10V_PLL10DIV2, 2, 1, -1},238	{M10V_SPI_PARENT1, M10V_PLL10DIV2, 4, 1, -1},239	{M10V_SPI_PARENT2, M10V_PLL7DIV2, 8, 1, -1},240	{M10V_UHS1CLK2_PARENT0, M10V_PLL7, 4, 1, -1},241	{M10V_UHS1CLK2_PARENT1, M10V_PLL7, 8, 1, -1},242	{M10V_UHS1CLK2_PARENT2, M10V_PLL7, 16, 1, -1},243	{M10V_UHS1CLK1_PARENT0, M10V_PLL7, 8, 1, -1},244	{M10V_UHS1CLK1_PARENT1, M10V_PLL7, 16, 1, -1},245	{M10V_NFCLK_PARENT0, M10V_PLL7DIV2, 8, 1, -1},246	{M10V_NFCLK_PARENT1, M10V_PLL7DIV2, 10, 1, -1},247	{M10V_NFCLK_PARENT2, M10V_PLL7DIV2, 13, 1, -1},248	{M10V_NFCLK_PARENT3, M10V_PLL7DIV2, 16, 1, -1},249	{M10V_NFCLK_PARENT4, M10V_PLL7DIV2, 40, 1, -1},250	{M10V_NFCLK_PARENT5, M10V_PLL7DIV5, 10, 1, -1},251};252 253static const struct m10v_clk_div_factors m10v_div_factor_data[] = {254	{"emmc", M10V_PLL11, CLKSEL(1), 28, 3, emmcclk_table, 0,255		M10V_EMMCCLK_ID},256	{"mclk400", M10V_PLL1DIV2, CLKSEL(10), 7, 3, mclk400_table, 0, -1},257	{"mclk200", M10V_PLL1DIV2, CLKSEL(10), 3, 4, mclk200_table, 0, -1},258	{"aclk400", M10V_PLL1DIV2, CLKSEL(10), 0, 3, aclk400_table, 0, -1},259	{"aclk300", M10V_PLL2DIV2, CLKSEL(12), 0, 2, aclk300_table, 0, -1},260	{"aclk", M10V_PLL1DIV2, CLKSEL(9), 20, 4, aclk_table, 0, M10V_ACLK_ID},261	{"aclkexs", M10V_PLL1DIV2, CLKSEL(9), 16, 4, aclkexs_table, 0, -1},262	{"hclk", M10V_PLL1DIV2, CLKSEL(9), 7, 5, hclk_table, 0, M10V_HCLK_ID},263	{"hclkbmh", M10V_PLL1DIV2, CLKSEL(9), 12, 4, hclkbmh_table, 0, -1},264	{"pclk", M10V_PLL1DIV2, CLKSEL(9), 0, 7, pclk_table, 0, M10V_PCLK_ID},265	{"uhs1clk0", M10V_PLL7, CLKSEL(1), 3, 5, uhs1clk0_table, 0, -1},266	{"uhs2clk", M10V_PLL6DIV3, CLKSEL(1), 18, 4, uhs2clk_table, 0, -1},267};268 269static const struct m10v_clk_mux_factors m10v_mux_factor_data[] = {270	{"spi", spi_mux_names, ARRAY_SIZE(spi_mux_names),271		CLKSEL(8), 3, 7, spi_mux_table, 0, M10V_SPICLK_ID},272	{"uhs1clk2", uhs1clk2_mux_names, ARRAY_SIZE(uhs1clk2_mux_names),273		CLKSEL(1), 13, 31, uhs1clk2_mux_table, 0, M10V_UHS1CLK2_ID},274	{"uhs1clk1", uhs1clk1_mux_names, ARRAY_SIZE(uhs1clk1_mux_names),275		CLKSEL(1), 8, 31, uhs1clk1_mux_table, 0, -1},276	{"nfclk", nfclk_mux_names, ARRAY_SIZE(nfclk_mux_names),277		CLKSEL(1), 22, 127, nfclk_mux_table, 0, M10V_NFCLK_ID},278};279 280static u8 m10v_mux_get_parent(struct clk_hw *hw)281{282	struct clk_mux *mux = to_clk_mux(hw);283	u32 val;284 285	val = readl(mux->reg) >> mux->shift;286	val &= mux->mask;287 288	return clk_mux_val_to_index(hw, mux->table, mux->flags, val);289}290 291static int m10v_mux_set_parent(struct clk_hw *hw, u8 index)292{293	struct clk_mux *mux = to_clk_mux(hw);294	u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);295	unsigned long flags = 0;296	u32 reg;297	u32 write_en = BIT(fls(mux->mask) - 1);298 299	if (mux->lock)300		spin_lock_irqsave(mux->lock, flags);301	else302		__acquire(mux->lock);303 304	reg = readl(mux->reg);305	reg &= ~(mux->mask << mux->shift);306 307	val = (val | write_en) << mux->shift;308	reg |= val;309	writel(reg, mux->reg);310 311	if (mux->lock)312		spin_unlock_irqrestore(mux->lock, flags);313	else314		__release(mux->lock);315 316	return 0;317}318 319static const struct clk_ops m10v_mux_ops = {320	.get_parent = m10v_mux_get_parent,321	.set_parent = m10v_mux_set_parent,322	.determine_rate = __clk_mux_determine_rate,323};324 325static struct clk_hw *m10v_clk_hw_register_mux(struct device *dev,326			const char *name, const char * const *parent_names,327			u8 num_parents, unsigned long flags, void __iomem *reg,328			u8 shift, u32 mask, u8 clk_mux_flags, u32 *table,329			spinlock_t *lock)330{331	struct clk_mux *mux;332	struct clk_hw *hw;333	struct clk_init_data init;334	int ret;335 336	mux = kzalloc(sizeof(*mux), GFP_KERNEL);337	if (!mux)338		return ERR_PTR(-ENOMEM);339 340	init.name = name;341	init.ops = &m10v_mux_ops;342	init.flags = flags;343	init.parent_names = parent_names;344	init.num_parents = num_parents;345 346	mux->reg = reg;347	mux->shift = shift;348	mux->mask = mask;349	mux->flags = clk_mux_flags;350	mux->lock = lock;351	mux->table = table;352	mux->hw.init = &init;353 354	hw = &mux->hw;355	ret = clk_hw_register(dev, hw);356	if (ret) {357		kfree(mux);358		hw = ERR_PTR(ret);359	}360 361	return hw;362 363}364 365struct m10v_clk_divider {366	struct clk_hw	hw;367	void __iomem	*reg;368	u8		shift;369	u8		width;370	u8		flags;371	const struct clk_div_table	*table;372	spinlock_t	*lock;373	void __iomem	*write_valid_reg;374};375 376static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw *hw,377		unsigned long parent_rate)378{379	struct m10v_clk_divider *divider = to_m10v_div(hw);380	unsigned int val;381 382	val = readl(divider->reg) >> divider->shift;383	val &= clk_div_mask(divider->width);384 385	return divider_recalc_rate(hw, parent_rate, val, divider->table,386				   divider->flags, divider->width);387}388 389static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,390				unsigned long *prate)391{392	struct m10v_clk_divider *divider = to_m10v_div(hw);393 394	/* if read only, just return current value */395	if (divider->flags & CLK_DIVIDER_READ_ONLY) {396		u32 val;397 398		val = readl(divider->reg) >> divider->shift;399		val &= clk_div_mask(divider->width);400 401		return divider_ro_round_rate(hw, rate, prate, divider->table,402					     divider->width, divider->flags,403					     val);404	}405 406	return divider_round_rate(hw, rate, prate, divider->table,407				  divider->width, divider->flags);408}409 410static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,411				unsigned long parent_rate)412{413	struct m10v_clk_divider *divider = to_m10v_div(hw);414	int value;415	unsigned long flags = 0;416	u32 val;417	u32 write_en = BIT(divider->width - 1);418 419	value = divider_get_val(rate, parent_rate, divider->table,420				divider->width, divider->flags);421	if (value < 0)422		return value;423 424	if (divider->lock)425		spin_lock_irqsave(divider->lock, flags);426	else427		__acquire(divider->lock);428 429	val = readl(divider->reg);430	val &= ~(clk_div_mask(divider->width) << divider->shift);431 432	val |= ((u32)value | write_en) << divider->shift;433	writel(val, divider->reg);434 435	if (divider->write_valid_reg) {436		writel(M10V_DCHREQ, divider->write_valid_reg);437		if (readl_poll_timeout(divider->write_valid_reg, val,438			!val, M10V_UPOLL_RATE, M10V_UTIMEOUT))439			pr_err("%s:%s couldn't stabilize\n",440				__func__, clk_hw_get_name(hw));441	}442 443	if (divider->lock)444		spin_unlock_irqrestore(divider->lock, flags);445	else446		__release(divider->lock);447 448	return 0;449}450 451static const struct clk_ops m10v_clk_divider_ops = {452	.recalc_rate = m10v_clk_divider_recalc_rate,453	.round_rate = m10v_clk_divider_round_rate,454	.set_rate = m10v_clk_divider_set_rate,455};456 457static struct clk_hw *m10v_clk_hw_register_divider(struct device *dev,458		const char *name, const char *parent_name, unsigned long flags,459		void __iomem *reg, u8 shift, u8 width,460		u8 clk_divider_flags, const struct clk_div_table *table,461		spinlock_t *lock, void __iomem *write_valid_reg)462{463	struct m10v_clk_divider *div;464	struct clk_hw *hw;465	struct clk_init_data init;466	int ret;467 468	div = kzalloc(sizeof(*div), GFP_KERNEL);469	if (!div)470		return ERR_PTR(-ENOMEM);471 472	init.name = name;473	init.ops = &m10v_clk_divider_ops;474	init.flags = flags;475	init.parent_names = &parent_name;476	init.num_parents = 1;477 478	div->reg = reg;479	div->shift = shift;480	div->width = width;481	div->flags = clk_divider_flags;482	div->lock = lock;483	div->hw.init = &init;484	div->table = table;485	div->write_valid_reg = write_valid_reg;486 487	/* register the clock */488	hw = &div->hw;489	ret = clk_hw_register(dev, hw);490	if (ret) {491		kfree(div);492		hw = ERR_PTR(ret);493	}494 495	return hw;496}497 498static void m10v_reg_div_pre(const struct m10v_clk_div_factors *factors,499			     struct clk_hw_onecell_data *clk_data,500			     void __iomem *base)501{502	struct clk_hw *hw;503	void __iomem *write_valid_reg;504 505	/*506	 * The registers on CLKSEL(9) or CLKSEL(10) need additional507	 * writing to become valid.508	 */509	if ((factors->offset == CLKSEL(9)) || (factors->offset == CLKSEL(10)))510		write_valid_reg = base + CLKSEL(11);511	else512		write_valid_reg = NULL;513 514	hw = m10v_clk_hw_register_divider(NULL, factors->name,515					  factors->parent_name,516					  CLK_SET_RATE_PARENT,517					  base + factors->offset,518					  factors->shift,519					  factors->width, factors->div_flags,520					  factors->table,521					  &m10v_crglock, write_valid_reg);522 523	if (factors->onecell_idx >= 0)524		clk_data->hws[factors->onecell_idx] = hw;525}526 527static void m10v_reg_fixed_pre(const struct m10v_clk_div_fixed_data *factors,528			       struct clk_hw_onecell_data *clk_data,529			       const char *parent_name)530{531	struct clk_hw *hw;532	const char *pn = factors->parent_name ?533				factors->parent_name : parent_name;534 535	hw = clk_hw_register_fixed_factor(NULL, factors->name, pn, 0,536					  factors->mult, factors->div);537 538	if (factors->onecell_idx >= 0)539		clk_data->hws[factors->onecell_idx] = hw;540}541 542static void m10v_reg_mux_pre(const struct m10v_clk_mux_factors *factors,543			       struct clk_hw_onecell_data *clk_data,544			       void __iomem *base)545{546	struct clk_hw *hw;547 548	hw = m10v_clk_hw_register_mux(NULL, factors->name,549				      factors->parent_names,550				      factors->num_parents,551				      CLK_SET_RATE_PARENT,552				      base + factors->offset, factors->shift,553				      factors->mask, factors->mux_flags,554				      factors->table, &m10v_crglock);555 556	if (factors->onecell_idx >= 0)557		clk_data->hws[factors->onecell_idx] = hw;558}559 560static int m10v_clk_probe(struct platform_device *pdev)561{562	int id;563	struct device *dev = &pdev->dev;564	struct device_node *np = dev->of_node;565	void __iomem *base;566	const char *parent_name;567 568	base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);569	if (IS_ERR(base))570		return PTR_ERR(base);571 572	parent_name = of_clk_get_parent_name(np, 0);573 574	for (id = 0; id < ARRAY_SIZE(m10v_div_factor_data); ++id)575		m10v_reg_div_pre(&m10v_div_factor_data[id],576				 m10v_clk_data, base);577 578	for (id = 0; id < ARRAY_SIZE(m10v_div_fixed_data); ++id)579		m10v_reg_fixed_pre(&m10v_div_fixed_data[id],580				   m10v_clk_data, parent_name);581 582	for (id = 0; id < ARRAY_SIZE(m10v_mux_factor_data); ++id)583		m10v_reg_mux_pre(&m10v_mux_factor_data[id],584				 m10v_clk_data, base);585 586	for (id = 0; id < M10V_NUM_CLKS; id++) {587		if (IS_ERR(m10v_clk_data->hws[id]))588			return PTR_ERR(m10v_clk_data->hws[id]);589	}590 591	return 0;592}593 594static const struct of_device_id m10v_clk_dt_ids[] = {595	{ .compatible = "socionext,milbeaut-m10v-ccu", },596	{ }597};598 599static struct platform_driver m10v_clk_driver = {600	.probe  = m10v_clk_probe,601	.driver = {602		.name = "m10v-ccu",603		.of_match_table = m10v_clk_dt_ids,604	},605};606builtin_platform_driver(m10v_clk_driver);607 608static void __init m10v_cc_init(struct device_node *np)609{610	int id;611	void __iomem *base;612	const char *parent_name;613	struct clk_hw *hw;614 615	m10v_clk_data = kzalloc(struct_size(m10v_clk_data, hws,616					M10V_NUM_CLKS),617					GFP_KERNEL);618 619	if (!m10v_clk_data)620		return;621	m10v_clk_data->num = M10V_NUM_CLKS;622 623	base = of_iomap(np, 0);624	if (!base) {625		kfree(m10v_clk_data);626		return;627	}628 629	parent_name = of_clk_get_parent_name(np, 0);630	if (!parent_name) {631		kfree(m10v_clk_data);632		iounmap(base);633		return;634	}635 636	/*637	 * This way all clocks fetched before the platform device probes,638	 * except those we assign here for early use, will be deferred.639	 */640	for (id = 0; id < M10V_NUM_CLKS; id++)641		m10v_clk_data->hws[id] = ERR_PTR(-EPROBE_DEFER);642 643	/*644	 * PLLs are set by bootloader so this driver registers them as the645	 * fixed factor.646	 */647	for (id = 0; id < ARRAY_SIZE(m10v_pll_fixed_data); ++id)648		m10v_reg_fixed_pre(&m10v_pll_fixed_data[id],649				   m10v_clk_data, parent_name);650 651	/*652	 * timer consumes "rclk" so it needs to register here.653	 */654	hw = m10v_clk_hw_register_divider(NULL, "rclk", M10V_PLL10DIV2, 0,655					base + CLKSEL(1), 0, 3, 0, rclk_table,656					&m10v_crglock, NULL);657	m10v_clk_data->hws[M10V_RCLK_ID] = hw;658	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, m10v_clk_data);659}660CLK_OF_DECLARE_DRIVER(m10v_cc, "socionext,milbeaut-m10v-ccu", m10v_cc_init);661