diff mbox series

[v2] i2c: bcm2835: Model Divider in CCF

Message ID 20190508071227.18609-1-nh6z@nh6z.net
State Superseded
Headers show
Series [v2] i2c: bcm2835: Model Divider in CCF | expand

Commit Message

Annaliese McDermond May 8, 2019, 7:12 a.m. UTC
Model the I2C bus clock divider as a part of the Core Clock Framework.
Primarily this removes the clk_get_rate() call from each transfer.
This call causes problems for slave drivers that themselves have
internal clock components that are controlled by an I2C interface.
When the slave's internal clock component is prepared, the prepare
lock is obtained, and it makes calls to the I2C subsystem to
command the hardware to activate the clock.  In order to perform
the I2C transfer, this driver sets the divider, which requires
it to get the parent clock rate, which it does with clk_get_rate().
Unfortunately, this function will try to take the clock prepare
lock, which is already held by the slave's internal clock calls
creating a deadlock.

Modeling the divider in the CCF natively removes this dependency
and the divider value is only set upon changing the bus clock
frequency or changes in the parent clock that cascade down to this
divisor.  This obviates the need to set the divider with every
transfer and avoids the deadlock described above.  It also should
provide better clock debugging and save a few cycles on each
transfer due to not having to recalcuate the divider value.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
Changes in v2:
 - Remove empty whitespace between declarations
 - Preserve comment regarding register rounding
 - Consolodate declarations and initial assignments
 - Return proper error pointer from bcm2835_i2c_register_div()
 - Properly handle return value from bcm2835_i2c_register_div()
   in bcm2835_i2c_probe()
 - Refactor divider calulation code into separate function
 - Use clk_set_rate_exclusive() to ensure the clock is not
   modified by other consumers
 - Deregister clock in bcm2835_i2c_remove() to properly clean up
   after ourselves

 drivers/i2c/busses/i2c-bcm2835.c | 144 ++++++++++++++++++++++++-------
 1 file changed, 113 insertions(+), 31 deletions(-)

Comments

Annaliese McDermond May 16, 2019, 5:37 a.m. UTC | #1
I’m just following up on this since I haven’t heard anything since I submitted the
v2 patch a week ago.  Wolfram, does this look like a sane approach?  Stefan,
were my changes in v2 acceptable?

I’m happy to go back to the drawing board to change things if there’s a better
answer to the problem.

Thanks for everyone’s patience with me trying to work through the proper
process.

--
Annaliese McDermond
nh6z@nh6z.net

> On May 8, 2019, at 12:12 AM, Annaliese McDermond <nh6z@nh6z.net> wrote:
> 
> Model the I2C bus clock divider as a part of the Core Clock Framework.
> Primarily this removes the clk_get_rate() call from each transfer.
> This call causes problems for slave drivers that themselves have
> internal clock components that are controlled by an I2C interface.
> When the slave's internal clock component is prepared, the prepare
> lock is obtained, and it makes calls to the I2C subsystem to
> command the hardware to activate the clock.  In order to perform
> the I2C transfer, this driver sets the divider, which requires
> it to get the parent clock rate, which it does with clk_get_rate().
> Unfortunately, this function will try to take the clock prepare
> lock, which is already held by the slave's internal clock calls
> creating a deadlock.
> 
> Modeling the divider in the CCF natively removes this dependency
> and the divider value is only set upon changing the bus clock
> frequency or changes in the parent clock that cascade down to this
> divisor.  This obviates the need to set the divider with every
> transfer and avoids the deadlock described above.  It also should
> provide better clock debugging and save a few cycles on each
> transfer due to not having to recalcuate the divider value.
> 
> Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
> ---
> Changes in v2:
> - Remove empty whitespace between declarations
> - Preserve comment regarding register rounding
> - Consolodate declarations and initial assignments
> - Return proper error pointer from bcm2835_i2c_register_div()
> - Properly handle return value from bcm2835_i2c_register_div()
>   in bcm2835_i2c_probe()
> - Refactor divider calulation code into separate function
> - Use clk_set_rate_exclusive() to ensure the clock is not
>   modified by other consumers
> - Deregister clock in bcm2835_i2c_remove() to properly clean up
>   after ourselves
> 
> drivers/i2c/busses/i2c-bcm2835.c | 144 ++++++++++++++++++++++++-------
> 1 file changed, 113 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
> index d2fbb4bb4a43..e66e569b8f09 100644
> --- a/drivers/i2c/busses/i2c-bcm2835.c
> +++ b/drivers/i2c/busses/i2c-bcm2835.c
> @@ -4,6 +4,8 @@
>  */
> 
> #include <linux/clk.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> #include <linux/completion.h>
> #include <linux/err.h>
> #include <linux/i2c.h>
> @@ -51,9 +53,7 @@
> struct bcm2835_i2c_dev {
> 	struct device *dev;
> 	void __iomem *regs;
> -	struct clk *clk;
> 	int irq;
> -	u32 bus_clk_rate;
> 	struct i2c_adapter adapter;
> 	struct completion completion;
> 	struct i2c_msg *curr_msg;
> @@ -74,12 +74,17 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
> 	return readl(i2c_dev->regs + reg);
> }
> 
> -static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
> +#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
> +struct clk_bcm2835_i2c {
> +	struct clk_hw hw;
> +	struct bcm2835_i2c_dev *i2c_dev;
> +};
> +
> +static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
> +				unsigned long parent_rate)
> {
> -	u32 divider, redl, fedl;
> +	u32 divider = DIV_ROUND_UP(parent_rate, rate);
> 
> -	divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
> -			       i2c_dev->bus_clk_rate);
> 	/*
> 	 * Per the datasheet, the register is always interpreted as an even
> 	 * number, by rounding down. In other words, the LSB is ignored. So,
> @@ -88,12 +93,23 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
> 	if (divider & 1)
> 		divider++;
> 	if ((divider < BCM2835_I2C_CDIV_MIN) ||
> -	    (divider > BCM2835_I2C_CDIV_MAX)) {
> -		dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
> +	    (divider > BCM2835_I2C_CDIV_MAX))
> 		return -EINVAL;
> -	}
> 
> -	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
> +	return divider;
> +}
> +
> +static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
> +				unsigned long parent_rate)
> +{
> +	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
> +	u32 redl, fedl;
> +	u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
> +
> +	if (divider == -EINVAL)
> +		return -EINVAL;
> +
> +	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
> 
> 	/*
> 	 * Number of core clocks to wait after falling edge before
> @@ -108,12 +124,60 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
> 	 */
> 	redl = max(divider / 4, 1u);
> 
> -	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
> +	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
> 			   (fedl << BCM2835_I2C_FEDL_SHIFT) |
> 			   (redl << BCM2835_I2C_REDL_SHIFT));
> 	return 0;
> }
> 
> +static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
> +				unsigned long *parent_rate)
> +{
> +	u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
> +
> +	return DIV_ROUND_UP(*parent_rate, divider);
> +}
> +
> +static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
> +						unsigned long parent_rate)
> +{
> +	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
> +	u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
> +
> +	return DIV_ROUND_UP(parent_rate, divider);
> +}
> +
> +static const struct clk_ops clk_bcm2835_i2c_ops = {
> +	.set_rate = clk_bcm2835_i2c_set_rate,
> +	.round_rate = clk_bcm2835_i2c_round_rate,
> +	.recalc_rate = clk_bcm2835_i2c_recalc_rate,
> +};
> +
> +static struct clk *bcm2835_i2c_register_div(struct device *dev,
> +					const char *mclk_name,
> +					struct bcm2835_i2c_dev *i2c_dev)
> +{
> +	struct clk_init_data init;
> +	struct clk_bcm2835_i2c *priv;
> +	const char *devname = dev_name(dev);
> +
> +	init.ops = &clk_bcm2835_i2c_ops;
> +	init.name = "bcm2835-i2c";
> +	init.parent_names = (const char* []) { mclk_name };
> +	init.num_parents = 1;
> +	init.flags = 0;
> +
> +	priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
> +	if (priv == NULL)
> +		return ERR_PTR(-ENOMEM);
> +
> +	priv->hw.init = &init;
> +	priv->i2c_dev = i2c_dev;
> +
> +	clk_hw_register_clkdev(&priv->hw, init.name, devname);
> +	return devm_clk_register(dev, &priv->hw);
> +}
> +
> static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
> {
> 	u32 val;
> @@ -271,7 +335,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
> {
> 	struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
> 	unsigned long time_left;
> -	int i, ret;
> +	int i;
> 
> 	for (i = 0; i < (num - 1); i++)
> 		if (msgs[i].flags & I2C_M_RD) {
> @@ -280,10 +344,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
> 			return -EOPNOTSUPP;
> 		}
> 
> -	ret = bcm2835_i2c_set_divider(i2c_dev);
> -	if (ret)
> -		return ret;
> -
> 	i2c_dev->curr_msg = msgs;
> 	i2c_dev->num_msgs = num;
> 	reinit_completion(&i2c_dev->completion);
> @@ -338,6 +398,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
> 	struct resource *mem, *irq;
> 	int ret;
> 	struct i2c_adapter *adap;
> +	const char *mclk_name;
> +	struct clk *bus_clk;
> +	u32 bus_clk_rate;
> 
> 	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
> 	if (!i2c_dev)
> @@ -351,21 +414,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
> 	if (IS_ERR(i2c_dev->regs))
> 		return PTR_ERR(i2c_dev->regs);
> 
> -	i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
> -	if (IS_ERR(i2c_dev->clk)) {
> -		if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
> -			dev_err(&pdev->dev, "Could not get clock\n");
> -		return PTR_ERR(i2c_dev->clk);
> -	}
> -
> -	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
> -				   &i2c_dev->bus_clk_rate);
> -	if (ret < 0) {
> -		dev_warn(&pdev->dev,
> -			 "Could not read clock-frequency property\n");
> -		i2c_dev->bus_clk_rate = 100000;
> -	}
> -
> 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> 	if (!irq) {
> 		dev_err(&pdev->dev, "No IRQ resource\n");
> @@ -380,6 +428,35 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
> 		return -ENODEV;
> 	}
> 
> +	mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
> +
> +	bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
> +
> +	if (IS_ERR(bus_clk)) {
> +		dev_err(&pdev->dev, "Could not register clock\n");
> +		return PTR_ERR(bus_clk);
> +	}
> +
> +	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
> +				   &bus_clk_rate);
> +	if (ret < 0) {
> +		dev_warn(&pdev->dev,
> +			 "Could not read clock-frequency property\n");
> +		bus_clk_rate = 100000;
> +	}
> +
> +	ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Could not set clock frequency\n");
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(bus_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Couldn't prepare clock");
> +		return ret;
> +	}
> +
> 	adap = &i2c_dev->adapter;
> 	i2c_set_adapdata(adap, i2c_dev);
> 	adap->owner = THIS_MODULE;
> @@ -402,6 +479,11 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
> static int bcm2835_i2c_remove(struct platform_device *pdev)
> {
> 	struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
> +	struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "bcm2835-i2c");
> +
> +	clk_rate_exclusive_put(bus_clk);
> +	clk_disable_unprepare(bus_clk);
> +	devm_clk_unregister(i2c_dev->dev, bus_clk);
> 
> 	free_irq(i2c_dev->irq, i2c_dev);
> 	i2c_del_adapter(&i2c_dev->adapter);
> -- 
> 2.19.1
>
Wolfram Sang May 16, 2019, 7:58 a.m. UTC | #2
Hi Annaliese,

On Wed, May 15, 2019 at 10:37:03PM -0700, Annaliese McDermond wrote:
> I’m just following up on this since I haven’t heard anything since I submitted the
> v2 patch a week ago.  Wolfram, does this look like a sane approach?  Stefan,
> were my changes in v2 acceptable?

There is a bit of overhead involved, but conceptually it looks like an
elegant solution to me. However, I am not an expert of CCF. Grepping
through kernel sources, I don't see many clocks defined outside
drivers/clk. So, I'd appreciate if we could get some ack/feedback from
one of the CCF experts/maintainers.

> I’m happy to go back to the drawing board to change things if there’s a better
> answer to the problem.
> 
> Thanks for everyone’s patience with me trying to work through the proper
> process.

Thanks for working on this one!

Kind regards,

   Wolfram
Stefan Wahren May 16, 2019, 10:59 a.m. UTC | #3
Hi Stephen,
hi Michael,

On 08.05.19 09:12, Annaliese McDermond wrote:
> Model the I2C bus clock divider as a part of the Core Clock Framework.
> Primarily this removes the clk_get_rate() call from each transfer.
> This call causes problems for slave drivers that themselves have
> internal clock components that are controlled by an I2C interface.
> When the slave's internal clock component is prepared, the prepare
> lock is obtained, and it makes calls to the I2C subsystem to
> command the hardware to activate the clock.  In order to perform
> the I2C transfer, this driver sets the divider, which requires
> it to get the parent clock rate, which it does with clk_get_rate().
> Unfortunately, this function will try to take the clock prepare
> lock, which is already held by the slave's internal clock calls
> creating a deadlock.
>
> Modeling the divider in the CCF natively removes this dependency
> and the divider value is only set upon changing the bus clock
> frequency or changes in the parent clock that cascade down to this
> divisor.  This obviates the need to set the divider with every
> transfer and avoids the deadlock described above.  It also should
> provide better clock debugging and save a few cycles on each
> transfer due to not having to recalcuate the divider value.
could you please take a look at this approach?
>
> Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
> ---
> Changes in v2:
>  - Remove empty whitespace between declarations
>  - Preserve comment regarding register rounding
>  - Consolodate declarations and initial assignments
>  - Return proper error pointer from bcm2835_i2c_register_div()
>  - Properly handle return value from bcm2835_i2c_register_div()
>    in bcm2835_i2c_probe()
>  - Refactor divider calulation code into separate function
>  - Use clk_set_rate_exclusive() to ensure the clock is not
>    modified by other consumers
>  - Deregister clock in bcm2835_i2c_remove() to properly clean up
>    after ourselves
>
>  drivers/i2c/busses/i2c-bcm2835.c | 144 ++++++++++++++++++++++++-------
>  1 file changed, 113 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
> index d2fbb4bb4a43..e66e569b8f09 100644
> --- a/drivers/i2c/busses/i2c-bcm2835.c
> +++ b/drivers/i2c/busses/i2c-bcm2835.c
> @@ -4,6 +4,8 @@
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
>  #include <linux/completion.h>
>  #include <linux/err.h>
>  #include <linux/i2c.h>
> @@ -51,9 +53,7 @@
>  struct bcm2835_i2c_dev {
>  	struct device *dev;
>  	void __iomem *regs;
> -	struct clk *clk;
>  	int irq;
> -	u32 bus_clk_rate;
>  	struct i2c_adapter adapter;
>  	struct completion completion;
>  	struct i2c_msg *curr_msg;
> @@ -74,12 +74,17 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
>  	return readl(i2c_dev->regs + reg);
>  }
>  
> -static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
> +#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
> +struct clk_bcm2835_i2c {
> +	struct clk_hw hw;
> +	struct bcm2835_i2c_dev *i2c_dev;
> +};
> +
> +static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
> +				unsigned long parent_rate)
>  {
> -	u32 divider, redl, fedl;
> +	u32 divider = DIV_ROUND_UP(parent_rate, rate);
>  
> -	divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
> -			       i2c_dev->bus_clk_rate);
>  	/*
>  	 * Per the datasheet, the register is always interpreted as an even
>  	 * number, by rounding down. In other words, the LSB is ignored. So,
> @@ -88,12 +93,23 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
>  	if (divider & 1)
>  		divider++;
>  	if ((divider < BCM2835_I2C_CDIV_MIN) ||
> -	    (divider > BCM2835_I2C_CDIV_MAX)) {
> -		dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
> +	    (divider > BCM2835_I2C_CDIV_MAX))
>  		return -EINVAL;
> -	}
>  
> -	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
> +	return divider;
> +}
> +
> +static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
> +				unsigned long parent_rate)
> +{
> +	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
> +	u32 redl, fedl;
> +	u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
> +
> +	if (divider == -EINVAL)
> +		return -EINVAL;
> +
> +	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
>  
>  	/*
>  	 * Number of core clocks to wait after falling edge before
> @@ -108,12 +124,60 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
>  	 */
>  	redl = max(divider / 4, 1u);
>  
> -	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
> +	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
>  			   (fedl << BCM2835_I2C_FEDL_SHIFT) |
>  			   (redl << BCM2835_I2C_REDL_SHIFT));
>  	return 0;
>  }
>  
> +static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
> +				unsigned long *parent_rate)
> +{
> +	u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
> +
> +	return DIV_ROUND_UP(*parent_rate, divider);
> +}
> +
> +static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
> +						unsigned long parent_rate)
> +{
> +	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
> +	u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
> +
> +	return DIV_ROUND_UP(parent_rate, divider);
> +}
> +
> +static const struct clk_ops clk_bcm2835_i2c_ops = {
> +	.set_rate = clk_bcm2835_i2c_set_rate,
> +	.round_rate = clk_bcm2835_i2c_round_rate,
> +	.recalc_rate = clk_bcm2835_i2c_recalc_rate,
> +};
> +
> +static struct clk *bcm2835_i2c_register_div(struct device *dev,
> +					const char *mclk_name,
> +					struct bcm2835_i2c_dev *i2c_dev)
> +{
> +	struct clk_init_data init;
> +	struct clk_bcm2835_i2c *priv;
> +	const char *devname = dev_name(dev);
> +
> +	init.ops = &clk_bcm2835_i2c_ops;
> +	init.name = "bcm2835-i2c";
> +	init.parent_names = (const char* []) { mclk_name };
> +	init.num_parents = 1;
> +	init.flags = 0;
> +
> +	priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
> +	if (priv == NULL)
> +		return ERR_PTR(-ENOMEM);
> +
> +	priv->hw.init = &init;
> +	priv->i2c_dev = i2c_dev;
> +
> +	clk_hw_register_clkdev(&priv->hw, init.name, devname);
> +	return devm_clk_register(dev, &priv->hw);
> +}
> +
>  static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
>  {
>  	u32 val;
> @@ -271,7 +335,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
>  {
>  	struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
>  	unsigned long time_left;
> -	int i, ret;
> +	int i;
>  
>  	for (i = 0; i < (num - 1); i++)
>  		if (msgs[i].flags & I2C_M_RD) {
> @@ -280,10 +344,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
>  			return -EOPNOTSUPP;
>  		}
>  
> -	ret = bcm2835_i2c_set_divider(i2c_dev);
> -	if (ret)
> -		return ret;
> -
>  	i2c_dev->curr_msg = msgs;
>  	i2c_dev->num_msgs = num;
>  	reinit_completion(&i2c_dev->completion);
> @@ -338,6 +398,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
>  	struct resource *mem, *irq;
>  	int ret;
>  	struct i2c_adapter *adap;
> +	const char *mclk_name;
> +	struct clk *bus_clk;
> +	u32 bus_clk_rate;
>  
>  	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
>  	if (!i2c_dev)
> @@ -351,21 +414,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
>  	if (IS_ERR(i2c_dev->regs))
>  		return PTR_ERR(i2c_dev->regs);
>  
> -	i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
> -	if (IS_ERR(i2c_dev->clk)) {
> -		if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
> -			dev_err(&pdev->dev, "Could not get clock\n");
> -		return PTR_ERR(i2c_dev->clk);
> -	}
> -
> -	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
> -				   &i2c_dev->bus_clk_rate);
> -	if (ret < 0) {
> -		dev_warn(&pdev->dev,
> -			 "Could not read clock-frequency property\n");
> -		i2c_dev->bus_clk_rate = 100000;
> -	}
> -
>  	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>  	if (!irq) {
>  		dev_err(&pdev->dev, "No IRQ resource\n");
> @@ -380,6 +428,35 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
>  		return -ENODEV;
>  	}
>  
> +	mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
> +
> +	bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
> +
> +	if (IS_ERR(bus_clk)) {
> +		dev_err(&pdev->dev, "Could not register clock\n");
> +		return PTR_ERR(bus_clk);
> +	}
> +
> +	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
> +				   &bus_clk_rate);
> +	if (ret < 0) {
> +		dev_warn(&pdev->dev,
> +			 "Could not read clock-frequency property\n");
> +		bus_clk_rate = 100000;
> +	}
> +
> +	ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Could not set clock frequency\n");
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(bus_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Couldn't prepare clock");
> +		return ret;
> +	}
> +
>  	adap = &i2c_dev->adapter;
>  	i2c_set_adapdata(adap, i2c_dev);
>  	adap->owner = THIS_MODULE;
> @@ -402,6 +479,11 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
>  static int bcm2835_i2c_remove(struct platform_device *pdev)
>  {
>  	struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
> +	struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "bcm2835-i2c");
> +
> +	clk_rate_exclusive_put(bus_clk);
> +	clk_disable_unprepare(bus_clk);
> +	devm_clk_unregister(i2c_dev->dev, bus_clk);
>  
>  	free_irq(i2c_dev->irq, i2c_dev);
>  	i2c_del_adapter(&i2c_dev->adapter);
Annaliese McDermond May 17, 2019, 1:55 a.m. UTC | #4
Wolfram --

Thank you very much for your response.

> On May 16, 2019, at 12:58 AM, Wolfram Sang <wsa@the-dreams.de> wrote:
> 
> Hi Annaliese,
> 
> On Wed, May 15, 2019 at 10:37:03PM -0700, Annaliese McDermond wrote:
>> I’m just following up on this since I haven’t heard anything since I submitted the
>> v2 patch a week ago.  Wolfram, does this look like a sane approach?  Stefan,
>> were my changes in v2 acceptable?
> 
> There is a bit of overhead involved, but conceptually it looks like an
> elegant solution to me. However, I am not an expert of CCF. Grepping
> through kernel sources, I don't see many clocks defined outside
> drivers/clk. So, I'd appreciate if we could get some ack/feedback from
> one of the CCF experts/maintainers.

I was also similarly nervous about a clock provider being outside of 
drivers/clk, especially since one of the instances of that I wrote.

When writing this, there was a certain logic to putting this inside of
clk-bcm2835.c instead.  Eric may like this approach better because there
will probably be more code reuse of some of the dividers he uses in that
driver.  

My concern was surrounding the cross pollenation of the i2c and
clock drivers to a certain extent.  You have to be able to set the
FEDL_SHIFT and REDL_SHIFT registers when you change the clock rate.
You can’t do it in the transfer function like was done before because
it requires a call to clk_get_rate() which can deadlock in the
conditions I encountered.  You’d have to move those calls to the
clk-bcm2835 driver instead.

My nervousness surrounding moving the code into the clock driver
rather than the i2c driver is that I don’t know how dependent they
are on one another.  Do we anticipate that there may be a use for
the i2c-bcm2835 driver without the clk-bcm2835 driver?  Asking the
question very well may be premature optimization for a condition
that may never exist.  I’m thinking maybe Eric has some more
insight into this?

The other minor issue is that it’s going to require a change to the
bcm2835 DT to change the clock pointer to the divider.

If it fits better in the clk-bcm2835 driver, I’m happy to submit a
patch that puts it there.  Just let me know and I can work on it.

--
Annaliese McDermond
nh6z@nh6z.net
Wolfram Sang May 27, 2019, 7:15 p.m. UTC | #5
Annaliese,

> Thank you very much for your response.

You are welcome.
> I was also similarly nervous about a clock provider being outside of 
> drivers/clk, especially since one of the instances of that I wrote.
> 
> When writing this, there was a certain logic to putting this inside of
> clk-bcm2835.c instead.  Eric may like this approach better because there
> will probably be more code reuse of some of the dividers he uses in that
> driver.  

Regardless which solution is favoured, I am going to apply this patch in
a minute:

http://patchwork.ozlabs.org/patch/1097688/

It enables this driver for ARCH_BRCMSTB. So, the solution should work
for this as well. (I don't know any of these platforms well)

Regards,

   Wolfram
Annaliese McDermond May 27, 2019, 8 p.m. UTC | #6
> On May 27, 2019, at 12:15 PM, Wolfram Sang <wsa@the-dreams.de> wrote:
> 
> Regardless which solution is favoured, I am going to apply this patch in
> a minute:
> 
> http://patchwork.ozlabs.org/patch/1097688/
> 
> It enables this driver for ARCH_BRCMSTB. So, the solution should work
> for this as well. (I don't know any of these platforms well)

I did some looking the other day, and I had forgotten that the RPi has 3
of the i2c-bcm2835 devices each with their own divider that sits in their
register space.  This makes me think the correct solution would be for
the divider to be controlled in the driver as was in my original patch.
Otherwise we’d have to make three different dividers in the bcm2835-clk
driver, and the i2c driver would no longer work for other platforms.

I haven’t heard any comments from any of the clock folks.  I was perusing
the code and I see there’s a SPI driver that registers its own clock and
some various ethernet and MMC drivers that do the same thing.

> Regards,
> 
>   Wolfram

--
Annaliese McDermond
nh6z@nh6z.net
Wolfram Sang May 27, 2019, 8:20 p.m. UTC | #7
On Mon, May 27, 2019 at 01:00:00PM -0700, Annaliese McDermond wrote:
> 
> > On May 27, 2019, at 12:15 PM, Wolfram Sang <wsa@the-dreams.de> wrote:
> > 
> > Regardless which solution is favoured, I am going to apply this patch in
> > a minute:
> > 
> > http://patchwork.ozlabs.org/patch/1097688/
> > 
> > It enables this driver for ARCH_BRCMSTB. So, the solution should work
> > for this as well. (I don't know any of these platforms well)
> 
> I did some looking the other day, and I had forgotten that the RPi has 3
> of the i2c-bcm2835 devices each with their own divider that sits in their
> register space.  This makes me think the correct solution would be for
> the divider to be controlled in the driver as was in my original patch.
> Otherwise we’d have to make three different dividers in the bcm2835-clk
> driver, and the i2c driver would no longer work for other platforms.

I am getting more and more convinced of the original patch even without
CCF acks. Others?
Stefan Wahren May 28, 2019, 7:52 a.m. UTC | #8
Hi Annaliese,

thank you for mention that we have multiple I2C interfaces.

On 08.05.19 09:12, Annaliese McDermond wrote:
> +
> +static struct clk *bcm2835_i2c_register_div(struct device *dev,
> +					const char *mclk_name,
> +					struct bcm2835_i2c_dev *i2c_dev)
> +{
> +	struct clk_init_data init;
> +	struct clk_bcm2835_i2c *priv;
> +	const char *devname = dev_name(dev);
> +
> +	init.ops = &clk_bcm2835_i2c_ops;
> +	init.name = "bcm2835-i2c";

Does this work intentionally in case i2c-0 and i2c-1 are used at the
same time?

Please also check the output of /sys/kernel/debug/clk/clk_summary

Regards
Stefan
Eric Anholt May 28, 2019, 10:25 p.m. UTC | #9
Annaliese McDermond <nh6z@nh6z.net> writes:

>> On May 27, 2019, at 12:15 PM, Wolfram Sang <wsa@the-dreams.de> wrote:
>> 
>> Regardless which solution is favoured, I am going to apply this patch in
>> a minute:
>> 
>> http://patchwork.ozlabs.org/patch/1097688/
>> 
>> It enables this driver for ARCH_BRCMSTB. So, the solution should work
>> for this as well. (I don't know any of these platforms well)
>
> I did some looking the other day, and I had forgotten that the RPi has 3
> of the i2c-bcm2835 devices each with their own divider that sits in their
> register space.  This makes me think the correct solution would be for
> the divider to be controlled in the driver as was in my original patch.
> Otherwise we’d have to make three different dividers in the bcm2835-clk
> driver, and the i2c driver would no longer work for other platforms.

Control of the divider should definitely be in the i2c driver, not in
clk-bcm2835.
Annaliese McDermond May 29, 2019, 3:01 a.m. UTC | #10
> On May 28, 2019, at 12:52 AM, Stefan Wahren <stefan.wahren@i2se.com> wrote:
> 
> Hi Annaliese,
> 
> thank you for mention that we have multiple I2C interfaces.
> 
> On 08.05.19 09:12, Annaliese McDermond wrote:
>> +
>> +static struct clk *bcm2835_i2c_register_div(struct device *dev,
>> +					const char *mclk_name,
>> +					struct bcm2835_i2c_dev *i2c_dev)
>> +{
>> +	struct clk_init_data init;
>> +	struct clk_bcm2835_i2c *priv;
>> +	const char *devname = dev_name(dev);
>> +
>> +	init.ops = &clk_bcm2835_i2c_ops;
>> +	init.name = "bcm2835-i2c";
> 
> Does this work intentionally in case i2c-0 and i2c-1 are used at the
> same time?

It should work fine.  The clocks are all registered separately and passed
the pointer to the struct device for the interface.  This keeps it
accessing the correct registers and such.

> Please also check the output of /sys/kernel/debug/clk/clk_summary

They’ll come up with the same name in the current code in the debug
output.  I agree this is mildly confusing and I’ll spin another version
of the patch to give them unique clock names in clk_summary.

> Regards
> Stefan
> 

--
Annaliese McDermonod
nh6z@nh6z.net
Annaliese McDermond May 29, 2019, 4:32 a.m. UTC | #11
> On May 28, 2019, at 8:01 PM, Annaliese McDermond <nh6z@nh6z.net> wrote:
> 
> 
> 
>> On May 28, 2019, at 12:52 AM, Stefan Wahren <stefan.wahren@i2se.com> wrote:

>> Please also check the output of /sys/kernel/debug/clk/clk_summary
> 
> They’ll come up with the same name in the current code in the debug
> output.  I agree this is mildly confusing and I’ll spin another version
> of the patch to give them unique clock names in clk_summary.

In v3 of the patch the output of /sys/kernel/debug/clk/clk_summary looks like the
following with two i2c devices enabled on the RPi.  Note 3f804000.i2c_div and 
3f205000.i2c_div.

                                 enable  prepare  protect                                duty
   clock                          count    count    count        rate   accuracy phase  cycle
---------------------------------------------------------------------------------------------
 otg                                  0        0        0   480000000          0     0  50000
 osc                                  7        7        4    19200000          0     0  50000
    gp2                               1        1        1       32768          0     0  50000
    tsens                             1        1        1     1920000          0     0  50000
    vec                               0        0        0    19200000          0     0  50000
    otp                               0        0        0     4800000          0     0  50000
    timer                             0        0        0     1000002          0     0  50000
    pllh                              4        4        0   855000000          0     0  50000
       pllh_pix_prediv                1        1        0   855000000          0     0  50000
          pllh_pix                    0        0        0    85500000          0     0  50000
       pllh_aux                       1        1        0     3339844          0     0  50000
       pllh_rcal_prediv               1        1        0     3339844          0     0  50000
          pllh_rcal                   0        0        0      333984          0     0  50000
    plld                              3        3        1  2000000024          0     0  50000
       plld_dsi1                      0        0        0     7812501          0     0  50000
       plld_dsi0                      0        0        0     7812501          0     0  50000
       plld_per                       4        4        3   500000006          0     0  50000
          pcm                         1        1        1     1535999          0     0  50000
          gp0                         1        1        1    24999389          0     0  50000
             pll                      1        1        0    98303848          0     0  50000
                codec_clkin           2        2        0    98303848          0     0  50000
                   nadc               1        1        0    12287981          0     0  50000
                      madc            1        1        0     6143991          0     0  50000
                   ndac               1        1        0    12287981          0     0  50000
                      mdac            2        2        0     6143991          0     0  50000
                         bdiv         1        1        0     1535998          0     0  50000
          gp1                         1        1        1    24000094          0     0  50000
          hsm                         0        0        0   163682866          0     0  50000
          uart                        0        0        0    47999625          0     0  50000
       plld_core                      2        2        0   500000006          0     0  50000
          sdram                       0        0        0   166666668          0     0  50000
    pllc                              3        3        1  2400000000          0     0  50000
       pllc_per                       1        1        0  1200000000          0     0  50000
          emmc                        0        0        0   200000000          0     0  50000
       pllc_core2                     0        0        0     9375000          0     0  50000
       pllc_core1                     0        0        0     9375000          0     0  50000
       pllc_core0                     2        2        1  1200000000          0     0  50000
          vpu                         3        3        2   400000000          0     0  50000
             3f804000.i2c_div         1        1        1      100000          0     0  50000
             3f205000.i2c_div         1        1        1      100000          0     0  50000
             aux_spi2                 0        0        0   400000000          0     0  50000
             aux_spi1                 0        0        0   400000000          0     0  50000
             aux_uart                 0        0        0   400000000          0     0  50000
             peri_image               0        0        0   400000000          0     0  50000
    pllb                              2        2        0  2800000012          0     0  50000
       pllb_arm                       1        1        0  1400000006          0     0  50000
    plla                              2        2        0  2400000000          0     0  50000
       plla_ccp2                      0        0        0     9375000          0     0  50000
       plla_dsi0                      0        0        0     9375000          0     0  50000
       plla_per                       0        0        0     9375000          0     0  50000
       plla_core                      1        1        0  1200000000          0     0  50000
          h264                        0        0        0   300000000          0     0  50000
          isp                         0        0        0   300000000          0     0  50000
          v3d                         0        0        0   300000000          0     0  50000
 sc16is752_clk                        1        1        0     1843200          0     0  50000
 dsi1p                                0        0        0           0          0     0  50000
 dsi0p                                0        0        0           0          0     0  50000
 dsi1e                                0        0        0           0          0     0  50000
 dsi0e                                0        0        0           0          0     0  50000
 cam1                                 0        0        0           0          0     0  50000
 cam0                                 0        0        0           0          0     0  50000
 dpi                                  0        0        0           0          0     0  50000
 tec                                  0        0        0           0          0     0  50000
 smi                                  0        0        0           0          0     0  50000
 slim                                 0        0        0           0          0     0  50000
 dft                                  0        0        0           0          0     0  50000
 aveo                                 0        0        0           0          0     0  50000
 pwm                                  0        0        0           0          0     0  50000

--
Annaliese McDermond
nh6z@nh6z.net
diff mbox series

Patch

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index d2fbb4bb4a43..e66e569b8f09 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -4,6 +4,8 @@ 
  */
 
 #include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/completion.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
@@ -51,9 +53,7 @@ 
 struct bcm2835_i2c_dev {
 	struct device *dev;
 	void __iomem *regs;
-	struct clk *clk;
 	int irq;
-	u32 bus_clk_rate;
 	struct i2c_adapter adapter;
 	struct completion completion;
 	struct i2c_msg *curr_msg;
@@ -74,12 +74,17 @@  static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
 	return readl(i2c_dev->regs + reg);
 }
 
-static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
+#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
+struct clk_bcm2835_i2c {
+	struct clk_hw hw;
+	struct bcm2835_i2c_dev *i2c_dev;
+};
+
+static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
+				unsigned long parent_rate)
 {
-	u32 divider, redl, fedl;
+	u32 divider = DIV_ROUND_UP(parent_rate, rate);
 
-	divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
-			       i2c_dev->bus_clk_rate);
 	/*
 	 * Per the datasheet, the register is always interpreted as an even
 	 * number, by rounding down. In other words, the LSB is ignored. So,
@@ -88,12 +93,23 @@  static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
 	if (divider & 1)
 		divider++;
 	if ((divider < BCM2835_I2C_CDIV_MIN) ||
-	    (divider > BCM2835_I2C_CDIV_MAX)) {
-		dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
+	    (divider > BCM2835_I2C_CDIV_MAX))
 		return -EINVAL;
-	}
 
-	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
+	return divider;
+}
+
+static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+	u32 redl, fedl;
+	u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
+
+	if (divider == -EINVAL)
+		return -EINVAL;
+
+	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
 
 	/*
 	 * Number of core clocks to wait after falling edge before
@@ -108,12 +124,60 @@  static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
 	 */
 	redl = max(divider / 4, 1u);
 
-	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
+	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
 			   (fedl << BCM2835_I2C_FEDL_SHIFT) |
 			   (redl << BCM2835_I2C_REDL_SHIFT));
 	return 0;
 }
 
+static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate)
+{
+	u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
+
+	return DIV_ROUND_UP(*parent_rate, divider);
+}
+
+static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+	u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
+
+	return DIV_ROUND_UP(parent_rate, divider);
+}
+
+static const struct clk_ops clk_bcm2835_i2c_ops = {
+	.set_rate = clk_bcm2835_i2c_set_rate,
+	.round_rate = clk_bcm2835_i2c_round_rate,
+	.recalc_rate = clk_bcm2835_i2c_recalc_rate,
+};
+
+static struct clk *bcm2835_i2c_register_div(struct device *dev,
+					const char *mclk_name,
+					struct bcm2835_i2c_dev *i2c_dev)
+{
+	struct clk_init_data init;
+	struct clk_bcm2835_i2c *priv;
+	const char *devname = dev_name(dev);
+
+	init.ops = &clk_bcm2835_i2c_ops;
+	init.name = "bcm2835-i2c";
+	init.parent_names = (const char* []) { mclk_name };
+	init.num_parents = 1;
+	init.flags = 0;
+
+	priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
+	if (priv == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	priv->hw.init = &init;
+	priv->i2c_dev = i2c_dev;
+
+	clk_hw_register_clkdev(&priv->hw, init.name, devname);
+	return devm_clk_register(dev, &priv->hw);
+}
+
 static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
 {
 	u32 val;
@@ -271,7 +335,7 @@  static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 {
 	struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	unsigned long time_left;
-	int i, ret;
+	int i;
 
 	for (i = 0; i < (num - 1); i++)
 		if (msgs[i].flags & I2C_M_RD) {
@@ -280,10 +344,6 @@  static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 			return -EOPNOTSUPP;
 		}
 
-	ret = bcm2835_i2c_set_divider(i2c_dev);
-	if (ret)
-		return ret;
-
 	i2c_dev->curr_msg = msgs;
 	i2c_dev->num_msgs = num;
 	reinit_completion(&i2c_dev->completion);
@@ -338,6 +398,9 @@  static int bcm2835_i2c_probe(struct platform_device *pdev)
 	struct resource *mem, *irq;
 	int ret;
 	struct i2c_adapter *adap;
+	const char *mclk_name;
+	struct clk *bus_clk;
+	u32 bus_clk_rate;
 
 	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
 	if (!i2c_dev)
@@ -351,21 +414,6 @@  static int bcm2835_i2c_probe(struct platform_device *pdev)
 	if (IS_ERR(i2c_dev->regs))
 		return PTR_ERR(i2c_dev->regs);
 
-	i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2c_dev->clk)) {
-		if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "Could not get clock\n");
-		return PTR_ERR(i2c_dev->clk);
-	}
-
-	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-				   &i2c_dev->bus_clk_rate);
-	if (ret < 0) {
-		dev_warn(&pdev->dev,
-			 "Could not read clock-frequency property\n");
-		i2c_dev->bus_clk_rate = 100000;
-	}
-
 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!irq) {
 		dev_err(&pdev->dev, "No IRQ resource\n");
@@ -380,6 +428,35 @@  static int bcm2835_i2c_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
+
+	bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
+
+	if (IS_ERR(bus_clk)) {
+		dev_err(&pdev->dev, "Could not register clock\n");
+		return PTR_ERR(bus_clk);
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+				   &bus_clk_rate);
+	if (ret < 0) {
+		dev_warn(&pdev->dev,
+			 "Could not read clock-frequency property\n");
+		bus_clk_rate = 100000;
+	}
+
+	ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Could not set clock frequency\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(bus_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't prepare clock");
+		return ret;
+	}
+
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	adap->owner = THIS_MODULE;
@@ -402,6 +479,11 @@  static int bcm2835_i2c_probe(struct platform_device *pdev)
 static int bcm2835_i2c_remove(struct platform_device *pdev)
 {
 	struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "bcm2835-i2c");
+
+	clk_rate_exclusive_put(bus_clk);
+	clk_disable_unprepare(bus_clk);
+	devm_clk_unregister(i2c_dev->dev, bus_clk);
 
 	free_irq(i2c_dev->irq, i2c_dev);
 	i2c_del_adapter(&i2c_dev->adapter);