diff options
author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2014-03-04 11:28:37 -0500 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2014-03-05 11:29:19 -0500 |
commit | 370136bc67c3f502ec96446e502ba80b94150f9d (patch) | |
tree | 496a317839161e9af290463fc8f4b61c35287c52 /drivers/i2c | |
parent | 96c4b6bb5ddb03881dfc1c91410548432138d4ba (diff) |
i2c: mv64xxx: Add reset deassert call
The Allwinner A31 SoC using that IP has a reset controller maintaining
it reset unless told otherwise.
Add some optional reset support to the driver.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 21 |
2 files changed, 20 insertions, 2 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f5ed03164d86..70bcad941657 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -528,6 +528,7 @@ config I2C_MPC | |||
528 | config I2C_MV64XXX | 528 | config I2C_MV64XXX |
529 | tristate "Marvell mv64xxx I2C Controller" | 529 | tristate "Marvell mv64xxx I2C Controller" |
530 | depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI) | 530 | depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI) |
531 | select RESET_CONTROLLER | ||
531 | help | 532 | help |
532 | If you say yes to this option, support will be included for the | 533 | If you say yes to this option, support will be included for the |
533 | built-in I2C interface on the Marvell 64xxx line of host bridges. | 534 | built-in I2C interface on the Marvell 64xxx line of host bridges. |
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index d52d84937ad3..1bb69b6f746d 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/mv643xx_i2c.h> | 18 | #include <linux/mv643xx_i2c.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/reset.h> | ||
20 | #include <linux/io.h> | 21 | #include <linux/io.h> |
21 | #include <linux/of.h> | 22 | #include <linux/of.h> |
22 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
@@ -148,6 +149,7 @@ struct mv64xxx_i2c_data { | |||
148 | bool offload_enabled; | 149 | bool offload_enabled; |
149 | /* 5us delay in order to avoid repeated start timing violation */ | 150 | /* 5us delay in order to avoid repeated start timing violation */ |
150 | bool errata_delay; | 151 | bool errata_delay; |
152 | struct reset_control *rstc; | ||
151 | }; | 153 | }; |
152 | 154 | ||
153 | static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { | 155 | static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { |
@@ -759,6 +761,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, | |||
759 | } | 761 | } |
760 | drv_data->irq = irq_of_parse_and_map(np, 0); | 762 | drv_data->irq = irq_of_parse_and_map(np, 0); |
761 | 763 | ||
764 | drv_data->rstc = devm_reset_control_get(dev, NULL); | ||
765 | if (IS_ERR(drv_data->rstc)) { | ||
766 | if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) { | ||
767 | rc = -EPROBE_DEFER; | ||
768 | goto out; | ||
769 | } | ||
770 | } else { | ||
771 | reset_control_deassert(drv_data->rstc); | ||
772 | } | ||
773 | |||
762 | /* Its not yet defined how timeouts will be specified in device tree. | 774 | /* Its not yet defined how timeouts will be specified in device tree. |
763 | * So hard code the value to 1 second. | 775 | * So hard code the value to 1 second. |
764 | */ | 776 | */ |
@@ -845,7 +857,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) | |||
845 | } | 857 | } |
846 | if (drv_data->irq < 0) { | 858 | if (drv_data->irq < 0) { |
847 | rc = -ENXIO; | 859 | rc = -ENXIO; |
848 | goto exit_clk; | 860 | goto exit_reset; |
849 | } | 861 | } |
850 | 862 | ||
851 | drv_data->adapter.dev.parent = &pd->dev; | 863 | drv_data->adapter.dev.parent = &pd->dev; |
@@ -865,7 +877,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) | |||
865 | dev_err(&drv_data->adapter.dev, | 877 | dev_err(&drv_data->adapter.dev, |
866 | "mv64xxx: Can't register intr handler irq%d: %d\n", | 878 | "mv64xxx: Can't register intr handler irq%d: %d\n", |
867 | drv_data->irq, rc); | 879 | drv_data->irq, rc); |
868 | goto exit_clk; | 880 | goto exit_reset; |
869 | } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { | 881 | } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { |
870 | dev_err(&drv_data->adapter.dev, | 882 | dev_err(&drv_data->adapter.dev, |
871 | "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); | 883 | "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); |
@@ -876,6 +888,9 @@ mv64xxx_i2c_probe(struct platform_device *pd) | |||
876 | 888 | ||
877 | exit_free_irq: | 889 | exit_free_irq: |
878 | free_irq(drv_data->irq, drv_data); | 890 | free_irq(drv_data->irq, drv_data); |
891 | exit_reset: | ||
892 | if (pd->dev.of_node && !IS_ERR(drv_data->rstc)) | ||
893 | reset_control_assert(drv_data->rstc); | ||
879 | exit_clk: | 894 | exit_clk: |
880 | #if defined(CONFIG_HAVE_CLK) | 895 | #if defined(CONFIG_HAVE_CLK) |
881 | /* Not all platforms have a clk */ | 896 | /* Not all platforms have a clk */ |
@@ -894,6 +909,8 @@ mv64xxx_i2c_remove(struct platform_device *dev) | |||
894 | 909 | ||
895 | i2c_del_adapter(&drv_data->adapter); | 910 | i2c_del_adapter(&drv_data->adapter); |
896 | free_irq(drv_data->irq, drv_data); | 911 | free_irq(drv_data->irq, drv_data); |
912 | if (dev->dev.of_node && !IS_ERR(drv_data->rstc)) | ||
913 | reset_control_assert(drv_data->rstc); | ||
897 | #if defined(CONFIG_HAVE_CLK) | 914 | #if defined(CONFIG_HAVE_CLK) |
898 | /* Not all platforms have a clk */ | 915 | /* Not all platforms have a clk */ |
899 | if (!IS_ERR(drv_data->clk)) { | 916 | if (!IS_ERR(drv_data->clk)) { |