diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.19/950-0520-i2c-bcm2835-Model-Divider-in-CCF.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.19/950-0520-i2c-bcm2835-Model-Divider-in-CCF.patch | 270 |
1 files changed, 0 insertions, 270 deletions
diff --git a/target/linux/brcm2708/patches-4.19/950-0520-i2c-bcm2835-Model-Divider-in-CCF.patch b/target/linux/brcm2708/patches-4.19/950-0520-i2c-bcm2835-Model-Divider-in-CCF.patch deleted file mode 100644 index 4f1d114840..0000000000 --- a/target/linux/brcm2708/patches-4.19/950-0520-i2c-bcm2835-Model-Divider-in-CCF.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 77a612fb674f924495a3a9a36ea60fb30d86644a Mon Sep 17 00:00:00 2001 -From: Annaliese McDermond <nh6z@nh6z.net> -Date: Sat, 8 Jun 2019 10:14:43 -0700 -Subject: [PATCH 520/725] i2c: bcm2835: Model Divider in CCF - -Commit bebff81fb8b9216eb4fba22cf910553621ae3477 upstream. - -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> -Acked-by: Stefan Wahren <stefan.wahren@i2se.com> -Reviewed-by: Eric Anholt <eric@anholt.net> -Signed-off-by: Wolfram Sang <wsa@the-dreams.de> ---- - drivers/i2c/busses/i2c-bcm2835.c | 145 ++++++++++++++++++++++++------- - 1 file changed, 114 insertions(+), 31 deletions(-) - ---- a/drivers/i2c/busses/i2c-bcm2835.c -+++ b/drivers/i2c/busses/i2c-bcm2835.c -@@ -12,6 +12,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> -@@ -71,9 +73,7 @@ struct bcm2835_debug { - 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; -@@ -164,12 +164,17 @@ static inline u32 bcm2835_i2c_readl(stru - 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, -@@ -178,12 +183,23 @@ static int bcm2835_i2c_set_divider(struc - 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 -@@ -198,12 +214,62 @@ static int bcm2835_i2c_set_divider(struc - */ - 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; -+ 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); -+} -+ - static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev) - { - u32 val; -@@ -363,7 +429,7 @@ static int bcm2835_i2c_xfer(struct i2c_a - { - struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - unsigned long time_left; -- int i, ret; -+ int i; - - if (debug) - i2c_dev->debug_num_msgs = num; -@@ -379,10 +445,6 @@ static int bcm2835_i2c_xfer(struct i2c_a - 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); -@@ -443,6 +505,9 @@ static int bcm2835_i2c_probe(struct plat - 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) -@@ -456,21 +521,6 @@ static int bcm2835_i2c_probe(struct plat - 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"); -@@ -485,6 +535,35 @@ static int bcm2835_i2c_probe(struct plat - 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; -@@ -507,6 +586,10 @@ static int bcm2835_i2c_probe(struct plat - 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, "div"); -+ -+ clk_rate_exclusive_put(bus_clk); -+ clk_disable_unprepare(bus_clk); - - free_irq(i2c_dev->irq, i2c_dev); - i2c_del_adapter(&i2c_dev->adapter); |