Message ID | 20160805221035.12157-3-swarren@wwwdotorg.org |
---|---|
State | Accepted |
Commit | 3c27fa2193f761e93d64e3c538c6931e6172adef |
Delegated to: | Tom Warren |
Headers | show |
On 5 August 2016 at 16:10, Stephen Warren <swarren@wwwdotorg.org> wrote: > From: Bryan Wu <pengw@nvidia.com> > > clk/reset API was tested on T186 platform and previous chip like > T210/T124 will still use the old APIs. > > Signed-off-by: Bryan Wu <pengw@nvidia.com> > (swarren, simplified some ifdefs, removed indent level inside an ifdef) > (swarren, added comment about the ifdefs) > Signed-off-by: Stephen Warren <swarren@nvidia.com> > --- > v2: Add TODO comment describing the messy ifdefs. > --- > drivers/i2c/tegra_i2c.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 85 insertions(+), 4 deletions(-) Reviewed-by: Simon Glass <sjg@chromium.org>
Hello Stephen, Am 06.08.2016 um 00:10 schrieb Stephen Warren: > From: Bryan Wu <pengw@nvidia.com> > > clk/reset API was tested on T186 platform and previous chip like > T210/T124 will still use the old APIs. > > Signed-off-by: Bryan Wu <pengw@nvidia.com> > (swarren, simplified some ifdefs, removed indent level inside an ifdef) > (swarren, added comment about the ifdefs) > Signed-off-by: Stephen Warren <swarren@nvidia.com> > --- > v2: Add TODO comment describing the messy ifdefs. > --- > drivers/i2c/tegra_i2c.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 85 insertions(+), 4 deletions(-) Reviewed-by: Heiko Schocher <hs@denx.de> bye, Heiko > > diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c > index 2fa07f9c57c4..31ba263b7295 100644 > --- a/drivers/i2c/tegra_i2c.c > +++ b/drivers/i2c/tegra_i2c.c > @@ -12,13 +12,27 @@ > #include <fdtdec.h> > #include <i2c.h> > #include <asm/io.h> > +#ifdef CONFIG_TEGRA186 > +#include <clk.h> > +#include <reset.h> > +#else > #include <asm/arch/clock.h> > #include <asm/arch/funcmux.h> > -#include <asm/arch/gpio.h> > #include <asm/arch/pinmux.h> > #include <asm/arch-tegra/clk_rst.h> > +#endif > +#include <asm/arch/gpio.h> > #include <asm/arch-tegra/tegra_i2c.h> > > +/* > + * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that > + * should not be present. These are needed because newer Tegra SoCs support > + * only the standard clock/reset APIs, whereas older Tegra SoCs support only > + * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be > + * fixed to implement the standard APIs, and all drivers converted to solely > + * use the new standard APIs, with no ifdefs. > + */ > + > DECLARE_GLOBAL_DATA_PTR; > > enum i2c_type { > @@ -30,7 +44,12 @@ enum i2c_type { > /* Information about i2c controller */ > struct i2c_bus { > int id; > +#ifdef CONFIG_TEGRA186 > + struct reset_ctl reset_ctl; > + struct clk clk; > +#else > enum periph_id periph_id; > +#endif > int speed; > int pinmux_config; > struct i2c_control *control; > @@ -62,12 +81,41 @@ static void set_packet_mode(struct i2c_bus *i2c_bus) > static void i2c_reset_controller(struct i2c_bus *i2c_bus) > { > /* Reset I2C controller. */ > +#ifdef CONFIG_TEGRA186 > + reset_assert(&i2c_bus->reset_ctl); > + udelay(1); > + reset_deassert(&i2c_bus->reset_ctl); > + udelay(1); > +#else > reset_periph(i2c_bus->periph_id, 1); > +#endif > > /* re-program config register to packet mode */ > set_packet_mode(i2c_bus); > } > > +#ifdef CONFIG_TEGRA186 > +static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate) > +{ > + int ret; > + > + ret = reset_assert(&i2c_bus->reset_ctl); > + if (ret) > + return ret; > + ret = clk_enable(&i2c_bus->clk); > + if (ret) > + return ret; > + ret = clk_set_rate(&i2c_bus->clk, rate); > + if (IS_ERR_VALUE(ret)) > + return ret; > + ret = reset_deassert(&i2c_bus->reset_ctl); > + if (ret) > + return ret; > + > + return 0; > +} > +#endif > + > static void i2c_init_controller(struct i2c_bus *i2c_bus) > { > if (!i2c_bus->speed) > @@ -78,8 +126,12 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) > * here, in section 23.3.1, but in fact we seem to need a factor of > * 16 to get the right frequency. > */ > +#ifdef CONFIG_TEGRA186 > + i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8); > +#else > clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, > i2c_bus->speed * 2 * 8); > +#endif > > if (i2c_bus->type == TYPE_114) { > /* > @@ -94,12 +146,17 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) > * is running, we hang, and we need it for the new calc. > */ > int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16; > + unsigned rate = CLK_MULT_STD_FAST_MODE * > + (clk_div_stdfst_mode + 1) * i2c_bus->speed * 2; > debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__, > clk_div_stdfst_mode); > > +#ifdef CONFIG_TEGRA186 > + i2c_init_clock(i2c_bus, rate); > +#else > clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, > - CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) * > - i2c_bus->speed * 2); > + rate); > +#endif > } > > /* Reset I2C controller. */ > @@ -112,7 +169,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) > setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK); > } > > +#ifndef CONFIG_TEGRA186 > funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config); > +#endif > } > > static void send_packet_headers( > @@ -333,8 +392,12 @@ static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) > static int tegra_i2c_probe(struct udevice *dev) > { > struct i2c_bus *i2c_bus = dev_get_priv(dev); > +#ifdef CONFIG_TEGRA186 > + int ret; > +#else > const void *blob = gd->fdt_blob; > int node = dev->of_offset; > +#endif > bool is_dvc; > > i2c_bus->id = dev->seq; > @@ -345,6 +408,18 @@ static int tegra_i2c_probe(struct udevice *dev) > * We don't have a binding for pinmux yet. Leave it out for now. So > * far no one needs anything other than the default. > */ > +#ifdef CONFIG_TEGRA186 > + ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl); > + if (ret) { > + error("reset_get_by_name() failed: %d\n", ret); > + return ret; > + } > + ret = clk_get_by_name(dev, "i2c", &i2c_bus->clk); > + if (ret) { > + error("clk_get_by_name() failed: %d\n", ret); > + return ret; > + } > +#else > i2c_bus->pinmux_config = FUNCMUX_DEFAULT; > i2c_bus->periph_id = clock_decode_periph_id(blob, node); > > @@ -359,6 +434,7 @@ static int tegra_i2c_probe(struct udevice *dev) > */ > if (i2c_bus->periph_id == -1) > return -EINVAL; > +#endif > > is_dvc = dev_get_driver_data(dev) == TYPE_DVC; > if (is_dvc) { > @@ -370,7 +446,12 @@ static int tegra_i2c_probe(struct udevice *dev) > i2c_init_controller(i2c_bus); > debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", > is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, > - i2c_bus->periph_id, i2c_bus->speed); > +#ifndef CONFIG_TEGRA186 > + i2c_bus->periph_id, > +#else > + -1, > +#endif > + i2c_bus->speed); > > return 0; > } >
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 2fa07f9c57c4..31ba263b7295 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -12,13 +12,27 @@ #include <fdtdec.h> #include <i2c.h> #include <asm/io.h> +#ifdef CONFIG_TEGRA186 +#include <clk.h> +#include <reset.h> +#else #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> -#include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> #include <asm/arch-tegra/clk_rst.h> +#endif +#include <asm/arch/gpio.h> #include <asm/arch-tegra/tegra_i2c.h> +/* + * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that + * should not be present. These are needed because newer Tegra SoCs support + * only the standard clock/reset APIs, whereas older Tegra SoCs support only + * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be + * fixed to implement the standard APIs, and all drivers converted to solely + * use the new standard APIs, with no ifdefs. + */ + DECLARE_GLOBAL_DATA_PTR; enum i2c_type { @@ -30,7 +44,12 @@ enum i2c_type { /* Information about i2c controller */ struct i2c_bus { int id; +#ifdef CONFIG_TEGRA186 + struct reset_ctl reset_ctl; + struct clk clk; +#else enum periph_id periph_id; +#endif int speed; int pinmux_config; struct i2c_control *control; @@ -62,12 +81,41 @@ static void set_packet_mode(struct i2c_bus *i2c_bus) static void i2c_reset_controller(struct i2c_bus *i2c_bus) { /* Reset I2C controller. */ +#ifdef CONFIG_TEGRA186 + reset_assert(&i2c_bus->reset_ctl); + udelay(1); + reset_deassert(&i2c_bus->reset_ctl); + udelay(1); +#else reset_periph(i2c_bus->periph_id, 1); +#endif /* re-program config register to packet mode */ set_packet_mode(i2c_bus); } +#ifdef CONFIG_TEGRA186 +static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate) +{ + int ret; + + ret = reset_assert(&i2c_bus->reset_ctl); + if (ret) + return ret; + ret = clk_enable(&i2c_bus->clk); + if (ret) + return ret; + ret = clk_set_rate(&i2c_bus->clk, rate); + if (IS_ERR_VALUE(ret)) + return ret; + ret = reset_deassert(&i2c_bus->reset_ctl); + if (ret) + return ret; + + return 0; +} +#endif + static void i2c_init_controller(struct i2c_bus *i2c_bus) { if (!i2c_bus->speed) @@ -78,8 +126,12 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) * here, in section 23.3.1, but in fact we seem to need a factor of * 16 to get the right frequency. */ +#ifdef CONFIG_TEGRA186 + i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8); +#else clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, i2c_bus->speed * 2 * 8); +#endif if (i2c_bus->type == TYPE_114) { /* @@ -94,12 +146,17 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) * is running, we hang, and we need it for the new calc. */ int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16; + unsigned rate = CLK_MULT_STD_FAST_MODE * + (clk_div_stdfst_mode + 1) * i2c_bus->speed * 2; debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__, clk_div_stdfst_mode); +#ifdef CONFIG_TEGRA186 + i2c_init_clock(i2c_bus, rate); +#else clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, - CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) * - i2c_bus->speed * 2); + rate); +#endif } /* Reset I2C controller. */ @@ -112,7 +169,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK); } +#ifndef CONFIG_TEGRA186 funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config); +#endif } static void send_packet_headers( @@ -333,8 +392,12 @@ static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) static int tegra_i2c_probe(struct udevice *dev) { struct i2c_bus *i2c_bus = dev_get_priv(dev); +#ifdef CONFIG_TEGRA186 + int ret; +#else const void *blob = gd->fdt_blob; int node = dev->of_offset; +#endif bool is_dvc; i2c_bus->id = dev->seq; @@ -345,6 +408,18 @@ static int tegra_i2c_probe(struct udevice *dev) * We don't have a binding for pinmux yet. Leave it out for now. So * far no one needs anything other than the default. */ +#ifdef CONFIG_TEGRA186 + ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl); + if (ret) { + error("reset_get_by_name() failed: %d\n", ret); + return ret; + } + ret = clk_get_by_name(dev, "i2c", &i2c_bus->clk); + if (ret) { + error("clk_get_by_name() failed: %d\n", ret); + return ret; + } +#else i2c_bus->pinmux_config = FUNCMUX_DEFAULT; i2c_bus->periph_id = clock_decode_periph_id(blob, node); @@ -359,6 +434,7 @@ static int tegra_i2c_probe(struct udevice *dev) */ if (i2c_bus->periph_id == -1) return -EINVAL; +#endif is_dvc = dev_get_driver_data(dev) == TYPE_DVC; if (is_dvc) { @@ -370,7 +446,12 @@ static int tegra_i2c_probe(struct udevice *dev) i2c_init_controller(i2c_bus); debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, - i2c_bus->periph_id, i2c_bus->speed); +#ifndef CONFIG_TEGRA186 + i2c_bus->periph_id, +#else + -1, +#endif + i2c_bus->speed); return 0; }