diff options
author | Thomas Abraham <thomas.abraham@linaro.org> | 2011-09-13 00:16:05 -0400 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2011-10-29 06:21:22 -0400 |
commit | 5a5f50802f5a31b9e15de8df40d5621af970a560 (patch) | |
tree | 352998103500f8744520fabb65d41db9d4700aea /drivers/i2c | |
parent | 4fd81eb2d64295ab038a3ea9d44e0eac85a6648c (diff) |
i2c-s3c2410: Add device tree support
Add device tree probe support for Samsung's s3c2410 i2c driver.
Cc: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 110 |
1 files changed, 106 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 266dd83a3ec2..9c00ad1f50a2 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #include <linux/cpufreq.h> | 35 | #include <linux/cpufreq.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/io.h> | 37 | #include <linux/io.h> |
38 | #include <linux/of_i2c.h> | ||
39 | #include <linux/of_gpio.h> | ||
38 | 40 | ||
39 | #include <asm/irq.h> | 41 | #include <asm/irq.h> |
40 | 42 | ||
@@ -79,6 +81,7 @@ struct s3c24xx_i2c { | |||
79 | struct i2c_adapter adap; | 81 | struct i2c_adapter adap; |
80 | 82 | ||
81 | struct s3c2410_platform_i2c *pdata; | 83 | struct s3c2410_platform_i2c *pdata; |
84 | int gpios[2]; | ||
82 | #ifdef CONFIG_CPU_FREQ | 85 | #ifdef CONFIG_CPU_FREQ |
83 | struct notifier_block freq_transition; | 86 | struct notifier_block freq_transition; |
84 | #endif | 87 | #endif |
@@ -96,6 +99,12 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) | |||
96 | struct platform_device *pdev = to_platform_device(i2c->dev); | 99 | struct platform_device *pdev = to_platform_device(i2c->dev); |
97 | enum s3c24xx_i2c_type type; | 100 | enum s3c24xx_i2c_type type; |
98 | 101 | ||
102 | #ifdef CONFIG_OF | ||
103 | if (i2c->dev->of_node) | ||
104 | return of_device_is_compatible(i2c->dev->of_node, | ||
105 | "samsung,s3c2440-i2c"); | ||
106 | #endif | ||
107 | |||
99 | type = platform_get_device_id(pdev)->driver_data; | 108 | type = platform_get_device_id(pdev)->driver_data; |
100 | return type == TYPE_S3C2440; | 109 | return type == TYPE_S3C2440; |
101 | } | 110 | } |
@@ -742,6 +751,49 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) | |||
742 | } | 751 | } |
743 | #endif | 752 | #endif |
744 | 753 | ||
754 | #ifdef CONFIG_OF | ||
755 | static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) | ||
756 | { | ||
757 | int idx, gpio, ret; | ||
758 | |||
759 | for (idx = 0; idx < 2; idx++) { | ||
760 | gpio = of_get_gpio(i2c->dev->of_node, idx); | ||
761 | if (!gpio_is_valid(gpio)) { | ||
762 | dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); | ||
763 | goto free_gpio; | ||
764 | } | ||
765 | |||
766 | ret = gpio_request(gpio, "i2c-bus"); | ||
767 | if (ret) { | ||
768 | dev_err(i2c->dev, "gpio [%d] request failed\n", gpio); | ||
769 | goto free_gpio; | ||
770 | } | ||
771 | } | ||
772 | return 0; | ||
773 | |||
774 | free_gpio: | ||
775 | while (--idx >= 0) | ||
776 | gpio_free(i2c->gpios[idx]); | ||
777 | return -EINVAL; | ||
778 | } | ||
779 | |||
780 | static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) | ||
781 | { | ||
782 | unsigned int idx; | ||
783 | for (idx = 0; idx < 2; idx++) | ||
784 | gpio_free(i2c->gpios[idx]); | ||
785 | } | ||
786 | #else | ||
787 | static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) | ||
788 | { | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) | ||
793 | { | ||
794 | } | ||
795 | #endif | ||
796 | |||
745 | /* s3c24xx_i2c_init | 797 | /* s3c24xx_i2c_init |
746 | * | 798 | * |
747 | * initialise the controller, set the IO lines and frequency | 799 | * initialise the controller, set the IO lines and frequency |
@@ -761,6 +813,9 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
761 | 813 | ||
762 | if (pdata->cfg_gpio) | 814 | if (pdata->cfg_gpio) |
763 | pdata->cfg_gpio(to_platform_device(i2c->dev)); | 815 | pdata->cfg_gpio(to_platform_device(i2c->dev)); |
816 | else | ||
817 | if (s3c24xx_i2c_parse_dt_gpio(i2c)) | ||
818 | return -EINVAL; | ||
764 | 819 | ||
765 | /* write slave address */ | 820 | /* write slave address */ |
766 | 821 | ||
@@ -786,6 +841,34 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
786 | return 0; | 841 | return 0; |
787 | } | 842 | } |
788 | 843 | ||
844 | #ifdef CONFIG_OF | ||
845 | /* s3c24xx_i2c_parse_dt | ||
846 | * | ||
847 | * Parse the device tree node and retreive the platform data. | ||
848 | */ | ||
849 | |||
850 | static void | ||
851 | s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) | ||
852 | { | ||
853 | struct s3c2410_platform_i2c *pdata = i2c->pdata; | ||
854 | |||
855 | if (!np) | ||
856 | return; | ||
857 | |||
858 | pdata->bus_num = -1; /* i2c bus number is dynamically assigned */ | ||
859 | of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay); | ||
860 | of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr); | ||
861 | of_property_read_u32(np, "samsung,i2c-max-bus-freq", | ||
862 | (u32 *)&pdata->frequency); | ||
863 | } | ||
864 | #else | ||
865 | static void | ||
866 | s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) | ||
867 | { | ||
868 | return; | ||
869 | } | ||
870 | #endif | ||
871 | |||
789 | /* s3c24xx_i2c_probe | 872 | /* s3c24xx_i2c_probe |
790 | * | 873 | * |
791 | * called by the bus driver when a suitable device is found | 874 | * called by the bus driver when a suitable device is found |
@@ -798,10 +881,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
798 | struct resource *res; | 881 | struct resource *res; |
799 | int ret; | 882 | int ret; |
800 | 883 | ||
801 | pdata = pdev->dev.platform_data; | 884 | if (!pdev->dev.of_node) { |
802 | if (!pdata) { | 885 | pdata = pdev->dev.platform_data; |
803 | dev_err(&pdev->dev, "no platform data\n"); | 886 | if (!pdata) { |
804 | return -EINVAL; | 887 | dev_err(&pdev->dev, "no platform data\n"); |
888 | return -EINVAL; | ||
889 | } | ||
805 | } | 890 | } |
806 | 891 | ||
807 | i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); | 892 | i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); |
@@ -818,6 +903,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
818 | 903 | ||
819 | if (pdata) | 904 | if (pdata) |
820 | memcpy(i2c->pdata, pdata, sizeof(*pdata)); | 905 | memcpy(i2c->pdata, pdata, sizeof(*pdata)); |
906 | else | ||
907 | s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c); | ||
821 | 908 | ||
822 | strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); | 909 | strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); |
823 | i2c->adap.owner = THIS_MODULE; | 910 | i2c->adap.owner = THIS_MODULE; |
@@ -914,6 +1001,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
914 | */ | 1001 | */ |
915 | 1002 | ||
916 | i2c->adap.nr = i2c->pdata->bus_num; | 1003 | i2c->adap.nr = i2c->pdata->bus_num; |
1004 | i2c->adap.dev.of_node = pdev->dev.of_node; | ||
917 | 1005 | ||
918 | ret = i2c_add_numbered_adapter(&i2c->adap); | 1006 | ret = i2c_add_numbered_adapter(&i2c->adap); |
919 | if (ret < 0) { | 1007 | if (ret < 0) { |
@@ -921,6 +1009,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
921 | goto err_cpufreq; | 1009 | goto err_cpufreq; |
922 | } | 1010 | } |
923 | 1011 | ||
1012 | of_i2c_register_devices(&i2c->adap); | ||
924 | platform_set_drvdata(pdev, i2c); | 1013 | platform_set_drvdata(pdev, i2c); |
925 | 1014 | ||
926 | dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); | 1015 | dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); |
@@ -969,6 +1058,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) | |||
969 | iounmap(i2c->regs); | 1058 | iounmap(i2c->regs); |
970 | 1059 | ||
971 | release_resource(i2c->ioarea); | 1060 | release_resource(i2c->ioarea); |
1061 | s3c24xx_i2c_dt_gpio_free(i2c); | ||
972 | kfree(i2c->ioarea); | 1062 | kfree(i2c->ioarea); |
973 | kfree(i2c); | 1063 | kfree(i2c); |
974 | 1064 | ||
@@ -1022,6 +1112,17 @@ static struct platform_device_id s3c24xx_driver_ids[] = { | |||
1022 | }; | 1112 | }; |
1023 | MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); | 1113 | MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); |
1024 | 1114 | ||
1115 | #ifdef CONFIG_OF | ||
1116 | static const struct of_device_id s3c24xx_i2c_match[] = { | ||
1117 | { .compatible = "samsung,s3c2410-i2c" }, | ||
1118 | { .compatible = "samsung,s3c2440-i2c" }, | ||
1119 | {}, | ||
1120 | }; | ||
1121 | MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match); | ||
1122 | #else | ||
1123 | #define s3c24xx_i2c_match NULL | ||
1124 | #endif | ||
1125 | |||
1025 | static struct platform_driver s3c24xx_i2c_driver = { | 1126 | static struct platform_driver s3c24xx_i2c_driver = { |
1026 | .probe = s3c24xx_i2c_probe, | 1127 | .probe = s3c24xx_i2c_probe, |
1027 | .remove = s3c24xx_i2c_remove, | 1128 | .remove = s3c24xx_i2c_remove, |
@@ -1030,6 +1131,7 @@ static struct platform_driver s3c24xx_i2c_driver = { | |||
1030 | .owner = THIS_MODULE, | 1131 | .owner = THIS_MODULE, |
1031 | .name = "s3c-i2c", | 1132 | .name = "s3c-i2c", |
1032 | .pm = S3C24XX_DEV_PM_OPS, | 1133 | .pm = S3C24XX_DEV_PM_OPS, |
1134 | .of_match_table = s3c24xx_i2c_match, | ||
1033 | }, | 1135 | }, |
1034 | }; | 1136 | }; |
1035 | 1137 | ||