diff options
author | Olof Johansson <olof@lixom.net> | 2012-09-16 18:31:37 -0700 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-09-16 18:31:37 -0700 |
commit | 2e6185f1fea6cf88e9ce25cde1d6291ddfb3d4f0 (patch) | |
tree | c45ae7bace055c258fba5c4c6c0340b1e3f17f05 /drivers/i2c/busses | |
parent | 7405a749ae14f846cc2892c36d1a9343b0264b7c (diff) | |
parent | fd301cc4e5ba839050be135a178031bcd0d363a5 (diff) | |
download | blackbird-op-linux-2e6185f1fea6cf88e9ce25cde1d6291ddfb3d4f0.tar.gz blackbird-op-linux-2e6185f1fea6cf88e9ce25cde1d6291ddfb3d4f0.zip |
Merge tag 'tegra-for-3.7-drivers-i2c' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra into next/drivers
From Stephen Warren:
ARM: tegra: i2c driver enhancements mostly related to clocking
This branch contains a number of fixes and cleanups to the Tegra I2C
driver related to clocks. These are based on the common clock conversion
in order to avoid duplicating the clock driver changes before and after
the conversion. Finally, a bug-fix related to I2C_M_NOSTART is included.
This branch is based on previous pull request tegra-for-3.7-common-clk.
* tag 'tegra-for-3.7-drivers-i2c' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra:
i2c: tegra: dynamically control fast clk
i2c: tegra: I2_M_NOSTART functionality not supported in Tegra20
ARM: tegra: clock: remove unused clock entry for i2c
ARM: tegra: clock: add connection name in i2c clock entry
i2c: tegra: pass proper name for getting clock
ARM: tegra: clock: add i2c fast clock entry in clock table
ARM: Tegra: Add smp_twd clock for Tegra20
ARM: tegra: cpu-tegra: explicitly manage re-parenting
ARM: tegra: fix overflow in tegra20_pll_clk_round_rate()
ARM: tegra: Fix data type for io address
ARM: tegra: remove tegra_timer from tegra_list_clks
ARM: tegra30: clocks: fix the wrong tegra_audio_sync_clk_ops name
ARM: tegra: clocks: separate tegra_clk_32k_ops from Tegra20 and Tegra30
ARM: tegra: Remove duplicate code
ARM: tegra: Port tegra to generic clock framework
ARM: tegra: Add clk_tegra structure and helper functions
ARM: tegra: Rename tegra20 clock file
ARM: tegra20: Separate out clk ops and clk data
ARM: tegra30: Separate out clk ops and clk data
ARM: tegra: fix U16 divider range check
...
+ sync to v3.6-rc4
Resolved remove/modify conflict in arch/arm/mach-sa1100/leds-hackkit.c
caused by the sync with v3.6-rc4.
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/i2c-diolan-u2c.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 28 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 132 |
4 files changed, 113 insertions, 50 deletions
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index aedb94f34bf7..dae3ddfe7619 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -405,6 +405,7 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, } } } + ret = num; abort: sret = diolan_i2c_stop(dev); if (sret < 0 && ret >= 0) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 5e6f1eed4f83..61b00edacb08 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -350,10 +350,6 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) i2c_clk = clk_get_rate(dev->clk); - /* fallback to std. mode if machine has not provided it */ - if (dev->cfg.clk_freq == 0) - dev->cfg.clk_freq = 100000; - /* * The spec says, in case of std. mode the divider is * 2 whereas it is 3 for fast and fastplus mode of @@ -911,20 +907,32 @@ static const struct i2c_algorithm nmk_i2c_algo = { .functionality = nmk_i2c_functionality }; +static struct nmk_i2c_controller u8500_i2c = { + /* + * Slave data setup time; 250ns, 100ns, and 10ns, which + * is 14, 6 and 2 respectively for a 48Mhz i2c clock. + */ + .slsu = 0xe, + .tft = 1, /* Tx FIFO threshold */ + .rft = 8, /* Rx FIFO threshold */ + .clk_freq = 400000, /* fast mode operation */ + .timeout = 200, /* Slave response timeout(ms) */ + .sm = I2C_FREQ_MODE_FAST, +}; + static atomic_t adapter_id = ATOMIC_INIT(0); static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; - struct nmk_i2c_controller *pdata = - adev->dev.platform_data; + struct nmk_i2c_controller *pdata = adev->dev.platform_data; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; - if (!pdata) { - dev_warn(&adev->dev, "no platform data\n"); - return -ENODEV; - } + if (!pdata) + /* No i2c configuration found, using the default. */ + pdata = &u8500_i2c; + dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); if (!dev) { dev_err(&adev->dev, "cannot allocate memory\n"); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6849635b268a..5d19a49803c1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -584,7 +584,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) r = pm_runtime_get_sync(dev->dev); if (IS_ERR_VALUE(r)) - return r; + goto out; r = omap_i2c_wait_for_bb(dev); if (r < 0) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 66eb53fac202..f981ac4e6783 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/i2c-tegra.h> #include <linux/of_i2c.h> +#include <linux/of_device.h> #include <linux/module.h> #include <asm/unaligned.h> @@ -114,11 +115,21 @@ enum msg_end_type { }; /** + * struct tegra_i2c_hw_feature : Different HW support on Tegra + * @has_continue_xfer_support: Continue transfer supports. + */ + +struct tegra_i2c_hw_feature { + bool has_continue_xfer_support; +}; + +/** * struct tegra_i2c_dev - per device i2c context * @dev: device reference for power management + * @hw: Tegra i2c hw feature. * @adapter: core i2c layer adapter information - * @clk: clock reference for i2c controller - * @i2c_clk: clock reference for i2c bus + * @div_clk: clock reference for div clock of i2c controller. + * @fast_clk: clock reference for fast clock of i2c controller. * @base: ioremapped registers cookie * @cont_id: i2c controller id, used for for packet header * @irq: irq number of transfer complete interrupt @@ -133,9 +144,10 @@ enum msg_end_type { */ struct tegra_i2c_dev { struct device *dev; + const struct tegra_i2c_hw_feature *hw; struct i2c_adapter adapter; - struct clk *clk; - struct clk *i2c_clk; + struct clk *div_clk; + struct clk *fast_clk; void __iomem *base; int cont_id; int irq; @@ -351,16 +363,40 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) dvc_writel(i2c_dev, val, DVC_CTRL_REG1); } +static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) +{ + int ret; + ret = clk_prepare_enable(i2c_dev->fast_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, + "Enabling fast clk failed, err %d\n", ret); + return ret; + } + ret = clk_prepare_enable(i2c_dev->div_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, + "Enabling div clk failed, err %d\n", ret); + clk_disable_unprepare(i2c_dev->fast_clk); + } + return ret; +} + +static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) +{ + clk_disable_unprepare(i2c_dev->div_clk); + clk_disable_unprepare(i2c_dev->fast_clk); +} + static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val; int err = 0; - clk_prepare_enable(i2c_dev->clk); + tegra_i2c_clock_enable(i2c_dev); - tegra_periph_reset_assert(i2c_dev->clk); + tegra_periph_reset_assert(i2c_dev->div_clk); udelay(2); - tegra_periph_reset_deassert(i2c_dev->clk); + tegra_periph_reset_deassert(i2c_dev->div_clk); if (i2c_dev->is_dvc) tegra_dvc_init(i2c_dev); @@ -369,7 +405,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); - clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); + clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8); if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); @@ -387,7 +423,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (tegra_i2c_flush_fifos(i2c_dev)) err = -ETIMEDOUT; - clk_disable_unprepare(i2c_dev->clk); + tegra_i2c_clock_disable(i2c_dev); if (i2c_dev->irq_disabled) { i2c_dev->irq_disabled = 0; @@ -563,7 +599,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (i2c_dev->is_suspended) return -EBUSY; - clk_prepare_enable(i2c_dev->clk); + tegra_i2c_clock_enable(i2c_dev); for (i = 0; i < num; i++) { enum msg_end_type end_type = MSG_END_STOP; if (i < (num - 1)) { @@ -576,14 +612,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (ret) break; } - clk_disable_unprepare(i2c_dev->clk); + tegra_i2c_clock_disable(i2c_dev); return ret ?: i; } static u32 tegra_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART; + struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + u32 ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; + + if (i2c_dev->hw->has_continue_xfer_support) + ret |= I2C_FUNC_NOSTART; + return ret; } static const struct i2c_algorithm tegra_i2c_algo = { @@ -591,13 +632,32 @@ static const struct i2c_algorithm tegra_i2c_algo = { .functionality = tegra_i2c_func, }; +static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { + .has_continue_xfer_support = false, +}; + +static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { + .has_continue_xfer_support = true, +}; + +#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, + { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, + { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); +#endif + static int __devinit tegra_i2c_probe(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev; struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; struct resource *res; - struct clk *clk; - struct clk *i2c_clk; + struct clk *div_clk; + struct clk *fast_clk; const unsigned int *prop; void __iomem *base; int irq; @@ -622,16 +682,16 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) } irq = res->start; - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { + div_clk = devm_clk_get(&pdev->dev, "div-clk"); + if (IS_ERR(div_clk)) { dev_err(&pdev->dev, "missing controller clock"); - return PTR_ERR(clk); + return PTR_ERR(div_clk); } - i2c_clk = devm_clk_get(&pdev->dev, "i2c"); - if (IS_ERR(i2c_clk)) { + fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); + if (IS_ERR(fast_clk)) { dev_err(&pdev->dev, "missing bus clock"); - return PTR_ERR(i2c_clk); + return PTR_ERR(fast_clk); } i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); @@ -641,8 +701,8 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) } i2c_dev->base = base; - i2c_dev->clk = clk; - i2c_dev->i2c_clk = i2c_clk; + i2c_dev->div_clk = div_clk; + i2c_dev->fast_clk = fast_clk; i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; @@ -659,11 +719,18 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) i2c_dev->bus_clk_rate = be32_to_cpup(prop); } - if (pdev->dev.of_node) + i2c_dev->hw = &tegra20_i2c_hw; + + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_device(of_match_ptr(tegra_i2c_of_match), + &pdev->dev); + i2c_dev->hw = match->data; i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, "nvidia,tegra20-i2c-dvc"); - else if (pdev->id == 3) + } else if (pdev->id == 3) { i2c_dev->is_dvc = 1; + } init_completion(&i2c_dev->msg_complete); platform_set_drvdata(pdev, i2c_dev); @@ -681,8 +748,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) return ret; } - clk_prepare_enable(i2c_dev->i2c_clk); - i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); i2c_dev->adapter.owner = THIS_MODULE; i2c_dev->adapter.class = I2C_CLASS_HWMON; @@ -696,7 +761,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { dev_err(&pdev->dev, "Failed to add I2C adapter\n"); - clk_disable_unprepare(i2c_dev->i2c_clk); return ret; } @@ -712,7 +776,7 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int tegra_i2c_suspend(struct device *dev) { struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -751,16 +815,6 @@ static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); #define TEGRA_I2C_PM NULL #endif -#if defined(CONFIG_OF) -/* Match table for of_platform binding */ -static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { - { .compatible = "nvidia,tegra20-i2c", }, - { .compatible = "nvidia,tegra20-i2c-dvc", }, - {}, -}; -MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); -#endif - static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = __devexit_p(tegra_i2c_remove), |