xref: /openbmc/linux/drivers/clk/clk-si514.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28ce20e66SMike Looijmans /*
38ce20e66SMike Looijmans  * Driver for Silicon Labs Si514 Programmable Oscillator
48ce20e66SMike Looijmans  *
58ce20e66SMike Looijmans  * Copyright (C) 2015 Topic Embedded Products
68ce20e66SMike Looijmans  *
78ce20e66SMike Looijmans  * Author: Mike Looijmans <mike.looijmans@topic.nl>
88ce20e66SMike Looijmans  */
98ce20e66SMike Looijmans 
108ce20e66SMike Looijmans #include <linux/clk-provider.h>
118ce20e66SMike Looijmans #include <linux/delay.h>
128ce20e66SMike Looijmans #include <linux/module.h>
138ce20e66SMike Looijmans #include <linux/i2c.h>
148ce20e66SMike Looijmans #include <linux/regmap.h>
158ce20e66SMike Looijmans #include <linux/slab.h>
168ce20e66SMike Looijmans 
178ce20e66SMike Looijmans /* I2C registers */
188ce20e66SMike Looijmans #define SI514_REG_LP		0
198ce20e66SMike Looijmans #define SI514_REG_M_FRAC1	5
208ce20e66SMike Looijmans #define SI514_REG_M_FRAC2	6
218ce20e66SMike Looijmans #define SI514_REG_M_FRAC3	7
228ce20e66SMike Looijmans #define SI514_REG_M_INT_FRAC	8
238ce20e66SMike Looijmans #define SI514_REG_M_INT		9
248ce20e66SMike Looijmans #define SI514_REG_HS_DIV	10
258ce20e66SMike Looijmans #define SI514_REG_LS_HS_DIV	11
268ce20e66SMike Looijmans #define SI514_REG_OE_STATE	14
278ce20e66SMike Looijmans #define SI514_REG_RESET		128
288ce20e66SMike Looijmans #define SI514_REG_CONTROL	132
298ce20e66SMike Looijmans 
308ce20e66SMike Looijmans /* Register values */
318ce20e66SMike Looijmans #define SI514_RESET_RST		BIT(7)
328ce20e66SMike Looijmans 
338ce20e66SMike Looijmans #define SI514_CONTROL_FCAL	BIT(0)
348ce20e66SMike Looijmans #define SI514_CONTROL_OE	BIT(2)
358ce20e66SMike Looijmans 
368ce20e66SMike Looijmans #define SI514_MIN_FREQ	    100000U
378ce20e66SMike Looijmans #define SI514_MAX_FREQ	 250000000U
388ce20e66SMike Looijmans 
398ce20e66SMike Looijmans #define FXO		  31980000U
408ce20e66SMike Looijmans 
418ce20e66SMike Looijmans #define FVCO_MIN	2080000000U
428ce20e66SMike Looijmans #define FVCO_MAX	2500000000U
438ce20e66SMike Looijmans 
448ce20e66SMike Looijmans #define HS_DIV_MAX	1022
458ce20e66SMike Looijmans 
468ce20e66SMike Looijmans struct clk_si514 {
478ce20e66SMike Looijmans 	struct clk_hw hw;
488ce20e66SMike Looijmans 	struct regmap *regmap;
498ce20e66SMike Looijmans 	struct i2c_client *i2c_client;
508ce20e66SMike Looijmans };
518ce20e66SMike Looijmans #define to_clk_si514(_hw)	container_of(_hw, struct clk_si514, hw)
528ce20e66SMike Looijmans 
538ce20e66SMike Looijmans /* Multiplier/divider settings */
548ce20e66SMike Looijmans struct clk_si514_muldiv {
558ce20e66SMike Looijmans 	u32 m_frac;  /* 29-bit Fractional part of multiplier M */
568ce20e66SMike Looijmans 	u8 m_int; /* Integer part of multiplier M, 65..78 */
578ce20e66SMike Looijmans 	u8 ls_div_bits; /* 2nd divider, as 2^x */
588ce20e66SMike Looijmans 	u16 hs_div; /* 1st divider, must be even and 10<=x<=1022 */
598ce20e66SMike Looijmans };
608ce20e66SMike Looijmans 
618ce20e66SMike Looijmans /* Enables or disables the output driver */
si514_enable_output(struct clk_si514 * data,bool enable)628ce20e66SMike Looijmans static int si514_enable_output(struct clk_si514 *data, bool enable)
638ce20e66SMike Looijmans {
648ce20e66SMike Looijmans 	return regmap_update_bits(data->regmap, SI514_REG_CONTROL,
658ce20e66SMike Looijmans 		SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0);
668ce20e66SMike Looijmans }
678ce20e66SMike Looijmans 
si514_prepare(struct clk_hw * hw)68e8f127caSMike Looijmans static int si514_prepare(struct clk_hw *hw)
69e8f127caSMike Looijmans {
70e8f127caSMike Looijmans 	struct clk_si514 *data = to_clk_si514(hw);
71e8f127caSMike Looijmans 
72e8f127caSMike Looijmans 	return si514_enable_output(data, true);
73e8f127caSMike Looijmans }
74e8f127caSMike Looijmans 
si514_unprepare(struct clk_hw * hw)75e8f127caSMike Looijmans static void si514_unprepare(struct clk_hw *hw)
76e8f127caSMike Looijmans {
77e8f127caSMike Looijmans 	struct clk_si514 *data = to_clk_si514(hw);
78e8f127caSMike Looijmans 
79e8f127caSMike Looijmans 	si514_enable_output(data, false);
80e8f127caSMike Looijmans }
81e8f127caSMike Looijmans 
si514_is_prepared(struct clk_hw * hw)82e8f127caSMike Looijmans static int si514_is_prepared(struct clk_hw *hw)
83e8f127caSMike Looijmans {
84e8f127caSMike Looijmans 	struct clk_si514 *data = to_clk_si514(hw);
85e8f127caSMike Looijmans 	unsigned int val;
86e8f127caSMike Looijmans 	int err;
87e8f127caSMike Looijmans 
88e8f127caSMike Looijmans 	err = regmap_read(data->regmap, SI514_REG_CONTROL, &val);
89e8f127caSMike Looijmans 	if (err < 0)
90e8f127caSMike Looijmans 		return err;
91e8f127caSMike Looijmans 
92e8f127caSMike Looijmans 	return !!(val & SI514_CONTROL_OE);
93e8f127caSMike Looijmans }
94e8f127caSMike Looijmans 
958ce20e66SMike Looijmans /* Retrieve clock multiplier and dividers from hardware */
si514_get_muldiv(struct clk_si514 * data,struct clk_si514_muldiv * settings)968ce20e66SMike Looijmans static int si514_get_muldiv(struct clk_si514 *data,
978ce20e66SMike Looijmans 	struct clk_si514_muldiv *settings)
988ce20e66SMike Looijmans {
998ce20e66SMike Looijmans 	int err;
1008ce20e66SMike Looijmans 	u8 reg[7];
1018ce20e66SMike Looijmans 
1028ce20e66SMike Looijmans 	err = regmap_bulk_read(data->regmap, SI514_REG_M_FRAC1,
1038ce20e66SMike Looijmans 			reg, ARRAY_SIZE(reg));
1048ce20e66SMike Looijmans 	if (err)
1058ce20e66SMike Looijmans 		return err;
1068ce20e66SMike Looijmans 
1078ce20e66SMike Looijmans 	settings->m_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
1088ce20e66SMike Looijmans 			   (reg[3] & 0x1F) << 24;
1098ce20e66SMike Looijmans 	settings->m_int = (reg[4] & 0x3f) << 3 | reg[3] >> 5;
1108ce20e66SMike Looijmans 	settings->ls_div_bits = (reg[6] >> 4) & 0x07;
1118ce20e66SMike Looijmans 	settings->hs_div = (reg[6] & 0x03) << 8 | reg[5];
1128ce20e66SMike Looijmans 	return 0;
1138ce20e66SMike Looijmans }
1148ce20e66SMike Looijmans 
si514_set_muldiv(struct clk_si514 * data,struct clk_si514_muldiv * settings)1158ce20e66SMike Looijmans static int si514_set_muldiv(struct clk_si514 *data,
1168ce20e66SMike Looijmans 	struct clk_si514_muldiv *settings)
1178ce20e66SMike Looijmans {
1188ce20e66SMike Looijmans 	u8 lp;
1198ce20e66SMike Looijmans 	u8 reg[7];
1208ce20e66SMike Looijmans 	int err;
1218ce20e66SMike Looijmans 
1228ce20e66SMike Looijmans 	/* Calculate LP1/LP2 according to table 13 in the datasheet */
1238ce20e66SMike Looijmans 	/* 65.259980246 */
1248ce20e66SMike Looijmans 	if (settings->m_int < 65 ||
1258ce20e66SMike Looijmans 		(settings->m_int == 65 && settings->m_frac <= 139575831))
1268ce20e66SMike Looijmans 		lp = 0x22;
1278ce20e66SMike Looijmans 	/* 67.859763463 */
1288ce20e66SMike Looijmans 	else if (settings->m_int < 67 ||
1298ce20e66SMike Looijmans 		(settings->m_int == 67 && settings->m_frac <= 461581994))
1308ce20e66SMike Looijmans 		lp = 0x23;
1318ce20e66SMike Looijmans 	/* 72.937624981 */
1328ce20e66SMike Looijmans 	else if (settings->m_int < 72 ||
1338ce20e66SMike Looijmans 		(settings->m_int == 72 && settings->m_frac <= 503383578))
1348ce20e66SMike Looijmans 		lp = 0x33;
1358ce20e66SMike Looijmans 	/* 75.843265046 */
1368ce20e66SMike Looijmans 	else if (settings->m_int < 75 ||
1378ce20e66SMike Looijmans 		(settings->m_int == 75 && settings->m_frac <= 452724474))
1388ce20e66SMike Looijmans 		lp = 0x34;
1398ce20e66SMike Looijmans 	else
1408ce20e66SMike Looijmans 		lp = 0x44;
1418ce20e66SMike Looijmans 
1428ce20e66SMike Looijmans 	err = regmap_write(data->regmap, SI514_REG_LP, lp);
1438ce20e66SMike Looijmans 	if (err < 0)
1448ce20e66SMike Looijmans 		return err;
1458ce20e66SMike Looijmans 
1468ce20e66SMike Looijmans 	reg[0] = settings->m_frac;
1478ce20e66SMike Looijmans 	reg[1] = settings->m_frac >> 8;
1488ce20e66SMike Looijmans 	reg[2] = settings->m_frac >> 16;
1498ce20e66SMike Looijmans 	reg[3] = settings->m_frac >> 24 | settings->m_int << 5;
1508ce20e66SMike Looijmans 	reg[4] = settings->m_int >> 3;
1518ce20e66SMike Looijmans 	reg[5] = settings->hs_div;
1528ce20e66SMike Looijmans 	reg[6] = (settings->hs_div >> 8) | (settings->ls_div_bits << 4);
1538ce20e66SMike Looijmans 
1548ce20e66SMike Looijmans 	err = regmap_bulk_write(data->regmap, SI514_REG_HS_DIV, reg + 5, 2);
1558ce20e66SMike Looijmans 	if (err < 0)
1568ce20e66SMike Looijmans 		return err;
1578ce20e66SMike Looijmans 	/*
1588ce20e66SMike Looijmans 	 * Writing to SI514_REG_M_INT_FRAC triggers the clock change, so that
1598ce20e66SMike Looijmans 	 * must be written last
1608ce20e66SMike Looijmans 	 */
1618ce20e66SMike Looijmans 	return regmap_bulk_write(data->regmap, SI514_REG_M_FRAC1, reg, 5);
1628ce20e66SMike Looijmans }
1638ce20e66SMike Looijmans 
1648ce20e66SMike Looijmans /* Calculate divider settings for a given frequency */
si514_calc_muldiv(struct clk_si514_muldiv * settings,unsigned long frequency)1658ce20e66SMike Looijmans static int si514_calc_muldiv(struct clk_si514_muldiv *settings,
1668ce20e66SMike Looijmans 	unsigned long frequency)
1678ce20e66SMike Looijmans {
1688ce20e66SMike Looijmans 	u64 m;
1698ce20e66SMike Looijmans 	u32 ls_freq;
1708ce20e66SMike Looijmans 	u32 tmp;
1718ce20e66SMike Looijmans 	u8 res;
1728ce20e66SMike Looijmans 
1738ce20e66SMike Looijmans 	if ((frequency < SI514_MIN_FREQ) || (frequency > SI514_MAX_FREQ))
1748ce20e66SMike Looijmans 		return -EINVAL;
1758ce20e66SMike Looijmans 
1768ce20e66SMike Looijmans 	/* Determine the minimum value of LS_DIV and resulting target freq. */
1778ce20e66SMike Looijmans 	ls_freq = frequency;
1788ce20e66SMike Looijmans 	if (frequency >= (FVCO_MIN / HS_DIV_MAX))
1798ce20e66SMike Looijmans 		settings->ls_div_bits = 0;
1808ce20e66SMike Looijmans 	else {
1818ce20e66SMike Looijmans 		res = 1;
1828ce20e66SMike Looijmans 		tmp = 2 * HS_DIV_MAX;
1838ce20e66SMike Looijmans 		while (tmp <= (HS_DIV_MAX * 32)) {
1848ce20e66SMike Looijmans 			if ((frequency * tmp) >= FVCO_MIN)
1858ce20e66SMike Looijmans 				break;
1868ce20e66SMike Looijmans 			++res;
1878ce20e66SMike Looijmans 			tmp <<= 1;
1888ce20e66SMike Looijmans 		}
1898ce20e66SMike Looijmans 		settings->ls_div_bits = res;
1908ce20e66SMike Looijmans 		ls_freq = frequency << res;
1918ce20e66SMike Looijmans 	}
1928ce20e66SMike Looijmans 
1938ce20e66SMike Looijmans 	/* Determine minimum HS_DIV, round up to even number */
1948ce20e66SMike Looijmans 	settings->hs_div = DIV_ROUND_UP(FVCO_MIN >> 1, ls_freq) << 1;
1958ce20e66SMike Looijmans 
1968ce20e66SMike Looijmans 	/* M = LS_DIV x HS_DIV x frequency / F_XO (in fixed-point) */
1978ce20e66SMike Looijmans 	m = ((u64)(ls_freq * settings->hs_div) << 29) + (FXO / 2);
1988ce20e66SMike Looijmans 	do_div(m, FXO);
1998ce20e66SMike Looijmans 	settings->m_frac = (u32)m & (BIT(29) - 1);
2008ce20e66SMike Looijmans 	settings->m_int = (u32)(m >> 29);
2018ce20e66SMike Looijmans 
2028ce20e66SMike Looijmans 	return 0;
2038ce20e66SMike Looijmans }
2048ce20e66SMike Looijmans 
2058ce20e66SMike Looijmans /* Calculate resulting frequency given the register settings */
si514_calc_rate(struct clk_si514_muldiv * settings)2068ce20e66SMike Looijmans static unsigned long si514_calc_rate(struct clk_si514_muldiv *settings)
2078ce20e66SMike Looijmans {
2088ce20e66SMike Looijmans 	u64 m = settings->m_frac | ((u64)settings->m_int << 29);
2098ce20e66SMike Looijmans 	u32 d = settings->hs_div * BIT(settings->ls_div_bits);
2108ce20e66SMike Looijmans 
2118ce20e66SMike Looijmans 	return ((u32)(((m * FXO) + (FXO / 2)) >> 29)) / d;
2128ce20e66SMike Looijmans }
2138ce20e66SMike Looijmans 
si514_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)2148ce20e66SMike Looijmans static unsigned long si514_recalc_rate(struct clk_hw *hw,
2158ce20e66SMike Looijmans 		unsigned long parent_rate)
2168ce20e66SMike Looijmans {
2178ce20e66SMike Looijmans 	struct clk_si514 *data = to_clk_si514(hw);
2188ce20e66SMike Looijmans 	struct clk_si514_muldiv settings;
2198ce20e66SMike Looijmans 	int err;
2208ce20e66SMike Looijmans 
2218ce20e66SMike Looijmans 	err = si514_get_muldiv(data, &settings);
2228ce20e66SMike Looijmans 	if (err) {
2238ce20e66SMike Looijmans 		dev_err(&data->i2c_client->dev, "unable to retrieve settings\n");
2248ce20e66SMike Looijmans 		return 0;
2258ce20e66SMike Looijmans 	}
2268ce20e66SMike Looijmans 
2278ce20e66SMike Looijmans 	return si514_calc_rate(&settings);
2288ce20e66SMike Looijmans }
2298ce20e66SMike Looijmans 
si514_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)2308ce20e66SMike Looijmans static long si514_round_rate(struct clk_hw *hw, unsigned long rate,
2318ce20e66SMike Looijmans 		unsigned long *parent_rate)
2328ce20e66SMike Looijmans {
2338ce20e66SMike Looijmans 	struct clk_si514_muldiv settings;
2348ce20e66SMike Looijmans 	int err;
2358ce20e66SMike Looijmans 
2368ce20e66SMike Looijmans 	if (!rate)
2378ce20e66SMike Looijmans 		return 0;
2388ce20e66SMike Looijmans 
2398ce20e66SMike Looijmans 	err = si514_calc_muldiv(&settings, rate);
2408ce20e66SMike Looijmans 	if (err)
2418ce20e66SMike Looijmans 		return err;
2428ce20e66SMike Looijmans 
2438ce20e66SMike Looijmans 	return si514_calc_rate(&settings);
2448ce20e66SMike Looijmans }
2458ce20e66SMike Looijmans 
2468ce20e66SMike Looijmans /*
2478ce20e66SMike Looijmans  * Update output frequency for big frequency changes (> 1000 ppm).
2488ce20e66SMike Looijmans  * The chip supports <1000ppm changes "on the fly", we haven't implemented
2498ce20e66SMike Looijmans  * that here.
2508ce20e66SMike Looijmans  */
si514_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)2518ce20e66SMike Looijmans static int si514_set_rate(struct clk_hw *hw, unsigned long rate,
2528ce20e66SMike Looijmans 		unsigned long parent_rate)
2538ce20e66SMike Looijmans {
2548ce20e66SMike Looijmans 	struct clk_si514 *data = to_clk_si514(hw);
2558ce20e66SMike Looijmans 	struct clk_si514_muldiv settings;
256e8f127caSMike Looijmans 	unsigned int old_oe_state;
2578ce20e66SMike Looijmans 	int err;
2588ce20e66SMike Looijmans 
2598ce20e66SMike Looijmans 	err = si514_calc_muldiv(&settings, rate);
2608ce20e66SMike Looijmans 	if (err)
2618ce20e66SMike Looijmans 		return err;
2628ce20e66SMike Looijmans 
263e8f127caSMike Looijmans 	err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state);
264e8f127caSMike Looijmans 	if (err)
265e8f127caSMike Looijmans 		return err;
266e8f127caSMike Looijmans 
2678ce20e66SMike Looijmans 	si514_enable_output(data, false);
2688ce20e66SMike Looijmans 
2698ce20e66SMike Looijmans 	err = si514_set_muldiv(data, &settings);
2708ce20e66SMike Looijmans 	if (err < 0)
2718ce20e66SMike Looijmans 		return err; /* Undefined state now, best to leave disabled */
2728ce20e66SMike Looijmans 
2738ce20e66SMike Looijmans 	/* Trigger calibration */
2748ce20e66SMike Looijmans 	err = regmap_write(data->regmap, SI514_REG_CONTROL, SI514_CONTROL_FCAL);
2758ce20e66SMike Looijmans 	if (err < 0)
2768ce20e66SMike Looijmans 		return err;
2778ce20e66SMike Looijmans 
2788ce20e66SMike Looijmans 	/* Applying a new frequency can take up to 10ms */
2798ce20e66SMike Looijmans 	usleep_range(10000, 12000);
2808ce20e66SMike Looijmans 
281e8f127caSMike Looijmans 	if (old_oe_state & SI514_CONTROL_OE)
2828ce20e66SMike Looijmans 		si514_enable_output(data, true);
2838ce20e66SMike Looijmans 
2848ce20e66SMike Looijmans 	return err;
2858ce20e66SMike Looijmans }
2868ce20e66SMike Looijmans 
2878ce20e66SMike Looijmans static const struct clk_ops si514_clk_ops = {
288e8f127caSMike Looijmans 	.prepare = si514_prepare,
289e8f127caSMike Looijmans 	.unprepare = si514_unprepare,
290e8f127caSMike Looijmans 	.is_prepared = si514_is_prepared,
2918ce20e66SMike Looijmans 	.recalc_rate = si514_recalc_rate,
2928ce20e66SMike Looijmans 	.round_rate = si514_round_rate,
2938ce20e66SMike Looijmans 	.set_rate = si514_set_rate,
2948ce20e66SMike Looijmans };
2958ce20e66SMike Looijmans 
si514_regmap_is_volatile(struct device * dev,unsigned int reg)2968ce20e66SMike Looijmans static bool si514_regmap_is_volatile(struct device *dev, unsigned int reg)
2978ce20e66SMike Looijmans {
2988ce20e66SMike Looijmans 	switch (reg) {
2998ce20e66SMike Looijmans 	case SI514_REG_CONTROL:
3008ce20e66SMike Looijmans 	case SI514_REG_RESET:
3018ce20e66SMike Looijmans 		return true;
3028ce20e66SMike Looijmans 	default:
3038ce20e66SMike Looijmans 		return false;
3048ce20e66SMike Looijmans 	}
3058ce20e66SMike Looijmans }
3068ce20e66SMike Looijmans 
si514_regmap_is_writeable(struct device * dev,unsigned int reg)3078ce20e66SMike Looijmans static bool si514_regmap_is_writeable(struct device *dev, unsigned int reg)
3088ce20e66SMike Looijmans {
3098ce20e66SMike Looijmans 	switch (reg) {
3108ce20e66SMike Looijmans 	case SI514_REG_LP:
3118ce20e66SMike Looijmans 	case SI514_REG_M_FRAC1 ... SI514_REG_LS_HS_DIV:
3128ce20e66SMike Looijmans 	case SI514_REG_OE_STATE:
3138ce20e66SMike Looijmans 	case SI514_REG_RESET:
3148ce20e66SMike Looijmans 	case SI514_REG_CONTROL:
3158ce20e66SMike Looijmans 		return true;
3168ce20e66SMike Looijmans 	default:
3178ce20e66SMike Looijmans 		return false;
3188ce20e66SMike Looijmans 	}
3198ce20e66SMike Looijmans }
3208ce20e66SMike Looijmans 
3218ce20e66SMike Looijmans static const struct regmap_config si514_regmap_config = {
3228ce20e66SMike Looijmans 	.reg_bits = 8,
3238ce20e66SMike Looijmans 	.val_bits = 8,
3248ce20e66SMike Looijmans 	.cache_type = REGCACHE_RBTREE,
3258ce20e66SMike Looijmans 	.max_register = SI514_REG_CONTROL,
3268ce20e66SMike Looijmans 	.writeable_reg = si514_regmap_is_writeable,
3278ce20e66SMike Looijmans 	.volatile_reg = si514_regmap_is_volatile,
3288ce20e66SMike Looijmans };
3298ce20e66SMike Looijmans 
si514_probe(struct i2c_client * client)330d8703ce8SStephen Kitt static int si514_probe(struct i2c_client *client)
3318ce20e66SMike Looijmans {
3328ce20e66SMike Looijmans 	struct clk_si514 *data;
3338ce20e66SMike Looijmans 	struct clk_init_data init;
3348ce20e66SMike Looijmans 	int err;
3358ce20e66SMike Looijmans 
3368ce20e66SMike Looijmans 	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
3378ce20e66SMike Looijmans 	if (!data)
3388ce20e66SMike Looijmans 		return -ENOMEM;
3398ce20e66SMike Looijmans 
3408ce20e66SMike Looijmans 	init.ops = &si514_clk_ops;
341803c4331SStephen Boyd 	init.flags = 0;
3428ce20e66SMike Looijmans 	init.num_parents = 0;
3438ce20e66SMike Looijmans 	data->hw.init = &init;
3448ce20e66SMike Looijmans 	data->i2c_client = client;
3458ce20e66SMike Looijmans 
3468ce20e66SMike Looijmans 	if (of_property_read_string(client->dev.of_node, "clock-output-names",
3478ce20e66SMike Looijmans 			&init.name))
3488ce20e66SMike Looijmans 		init.name = client->dev.of_node->name;
3498ce20e66SMike Looijmans 
3508ce20e66SMike Looijmans 	data->regmap = devm_regmap_init_i2c(client, &si514_regmap_config);
3518ce20e66SMike Looijmans 	if (IS_ERR(data->regmap)) {
3528ce20e66SMike Looijmans 		dev_err(&client->dev, "failed to allocate register map\n");
3538ce20e66SMike Looijmans 		return PTR_ERR(data->regmap);
3548ce20e66SMike Looijmans 	}
3558ce20e66SMike Looijmans 
3568ce20e66SMike Looijmans 	i2c_set_clientdata(client, data);
3578ce20e66SMike Looijmans 
358d06e46c2SStephen Boyd 	err = devm_clk_hw_register(&client->dev, &data->hw);
359d06e46c2SStephen Boyd 	if (err) {
3608ce20e66SMike Looijmans 		dev_err(&client->dev, "clock registration failed\n");
361d06e46c2SStephen Boyd 		return err;
3628ce20e66SMike Looijmans 	}
363*a7f3b675SLars-Peter Clausen 	err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get,
364d06e46c2SStephen Boyd 					  &data->hw);
3658ce20e66SMike Looijmans 	if (err) {
3668ce20e66SMike Looijmans 		dev_err(&client->dev, "unable to add clk provider\n");
3678ce20e66SMike Looijmans 		return err;
3688ce20e66SMike Looijmans 	}
3698ce20e66SMike Looijmans 
3708ce20e66SMike Looijmans 	return 0;
3718ce20e66SMike Looijmans }
3728ce20e66SMike Looijmans 
3738ce20e66SMike Looijmans static const struct i2c_device_id si514_id[] = {
3748ce20e66SMike Looijmans 	{ "si514", 0 },
3758ce20e66SMike Looijmans 	{ }
3768ce20e66SMike Looijmans };
3778ce20e66SMike Looijmans MODULE_DEVICE_TABLE(i2c, si514_id);
3788ce20e66SMike Looijmans 
3798ce20e66SMike Looijmans static const struct of_device_id clk_si514_of_match[] = {
3808ce20e66SMike Looijmans 	{ .compatible = "silabs,si514" },
3818ce20e66SMike Looijmans 	{ },
3828ce20e66SMike Looijmans };
3838ce20e66SMike Looijmans MODULE_DEVICE_TABLE(of, clk_si514_of_match);
3848ce20e66SMike Looijmans 
3858ce20e66SMike Looijmans static struct i2c_driver si514_driver = {
3868ce20e66SMike Looijmans 	.driver = {
3878ce20e66SMike Looijmans 		.name = "si514",
3888ce20e66SMike Looijmans 		.of_match_table = clk_si514_of_match,
3898ce20e66SMike Looijmans 	},
390d8703ce8SStephen Kitt 	.probe		= si514_probe,
3918ce20e66SMike Looijmans 	.id_table	= si514_id,
3928ce20e66SMike Looijmans };
3938ce20e66SMike Looijmans module_i2c_driver(si514_driver);
3948ce20e66SMike Looijmans 
3958ce20e66SMike Looijmans MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
3968ce20e66SMike Looijmans MODULE_DESCRIPTION("Si514 driver");
3978ce20e66SMike Looijmans MODULE_LICENSE("GPL");
398