+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;
+ char name[32];
+
+ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
+
+ init.ops = &clk_bcm2835_i2c_ops;
+ init.name = name;
+ 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, "div", dev_name(dev));
+ return devm_clk_register(dev, &priv->hw);
+}
+