diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2015-02-05 14:55:01 -0500 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2015-02-05 16:29:23 -0500 |
commit | e961a094afe04c6c8ca1adac50c8d16513f31b93 (patch) | |
tree | 2b5d803d08e759fe7f8202e3a1d098a60436fbf2 | |
parent | 181d9a07da1050d3da30c6936eb825724fefc18a (diff) |
i2c: ocores: add common clock support
Allow bus clock specification as a common clock handle. This makes this
controller easier to use in a setup based on common clock framework.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r-- | Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 32 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 33 |
2 files changed, 59 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index 5bef3adf2c35..17bef9a34e50 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt | |||
@@ -4,8 +4,10 @@ Required properties: | |||
4 | - compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst" | 4 | - compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst" |
5 | - reg : bus address start and address range size of device | 5 | - reg : bus address start and address range size of device |
6 | - interrupts : interrupt number | 6 | - interrupts : interrupt number |
7 | - clocks : handle to the controller clock; see the note below. | ||
8 | Mutually exclusive with opencores,ip-clock-frequency | ||
7 | - opencores,ip-clock-frequency: frequency of the controller clock in Hz; | 9 | - opencores,ip-clock-frequency: frequency of the controller clock in Hz; |
8 | see the note below | 10 | see the note below. Mutually exclusive with clocks |
9 | - #address-cells : should be <1> | 11 | - #address-cells : should be <1> |
10 | - #size-cells : should be <0> | 12 | - #size-cells : should be <0> |
11 | 13 | ||
@@ -20,14 +22,16 @@ Note | |||
20 | clock-frequency property is meant to control the bus frequency for i2c bus | 22 | clock-frequency property is meant to control the bus frequency for i2c bus |
21 | drivers, but it was incorrectly used to specify i2c controller input clock | 23 | drivers, but it was incorrectly used to specify i2c controller input clock |
22 | frequency. So the following rules are set to fix this situation: | 24 | frequency. So the following rules are set to fix this situation: |
23 | - if clock-frequency is present and opencores,ip-clock-frequency is not, | 25 | - if clock-frequency is present and neither opencores,ip-clock-frequency nor |
24 | then clock-frequency specifies i2c controller clock frequency. This is | 26 | clocks are, then clock-frequency specifies i2c controller clock frequency. |
25 | to keep backwards compatibility with setups using old DTB. i2c bus | 27 | This is to keep backwards compatibility with setups using old DTB. i2c bus |
26 | frequency is fixed at 100 KHz. | 28 | frequency is fixed at 100 KHz. |
29 | - if clocks is present it specifies i2c controller clock. clock-frequency | ||
30 | property specifies i2c bus frequency. | ||
27 | - if opencores,ip-clock-frequency is present it specifies i2c controller | 31 | - if opencores,ip-clock-frequency is present it specifies i2c controller |
28 | clock frequency. clock-frequency property specifies i2c bus frequency. | 32 | clock frequency. clock-frequency property specifies i2c bus frequency. |
29 | 33 | ||
30 | Example: | 34 | Examples: |
31 | 35 | ||
32 | i2c0: ocores@a0000000 { | 36 | i2c0: ocores@a0000000 { |
33 | #address-cells = <1>; | 37 | #address-cells = <1>; |
@@ -45,3 +49,21 @@ Example: | |||
45 | reg = <0x60>; | 49 | reg = <0x60>; |
46 | }; | 50 | }; |
47 | }; | 51 | }; |
52 | or | ||
53 | i2c0: ocores@a0000000 { | ||
54 | #address-cells = <1>; | ||
55 | #size-cells = <0>; | ||
56 | compatible = "opencores,i2c-ocores"; | ||
57 | reg = <0xa0000000 0x8>; | ||
58 | interrupts = <10>; | ||
59 | clocks = <&osc>; | ||
60 | clock-frequency = <400000>; /* i2c bus frequency 400 KHz */ | ||
61 | |||
62 | reg-shift = <0>; /* 8 bit registers */ | ||
63 | reg-io-width = <1>; /* 8 bit read/write */ | ||
64 | |||
65 | dummy@60 { | ||
66 | compatible = "dummy"; | ||
67 | reg = <0x60>; | ||
68 | }; | ||
69 | }; | ||
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 6cbbb134cfb7..3fc76b6ffcaa 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * kind, whether express or implied. | 12 | * kind, whether express or implied. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/clk.h> | ||
15 | #include <linux/err.h> | 16 | #include <linux/err.h> |
16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
@@ -35,6 +36,7 @@ struct ocores_i2c { | |||
35 | int pos; | 36 | int pos; |
36 | int nmsgs; | 37 | int nmsgs; |
37 | int state; /* see STATE_ */ | 38 | int state; /* see STATE_ */ |
39 | struct clk *clk; | ||
38 | int ip_clock_khz; | 40 | int ip_clock_khz; |
39 | int bus_clock_khz; | 41 | int bus_clock_khz; |
40 | void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); | 42 | void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); |
@@ -339,7 +341,21 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, | |||
339 | &clock_frequency); | 341 | &clock_frequency); |
340 | i2c->bus_clock_khz = 100; | 342 | i2c->bus_clock_khz = 100; |
341 | 343 | ||
342 | if (of_property_read_u32(np, "opencores,ip-clock-frequency", &val)) { | 344 | i2c->clk = devm_clk_get(&pdev->dev, NULL); |
345 | |||
346 | if (!IS_ERR(i2c->clk)) { | ||
347 | int ret = clk_prepare_enable(i2c->clk); | ||
348 | |||
349 | if (ret) { | ||
350 | dev_err(&pdev->dev, | ||
351 | "clk_prepare_enable failed: %d\n", ret); | ||
352 | return ret; | ||
353 | } | ||
354 | i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; | ||
355 | if (clock_frequency_present) | ||
356 | i2c->bus_clock_khz = clock_frequency / 1000; | ||
357 | } else if (of_property_read_u32(np, "opencores,ip-clock-frequency", | ||
358 | &val)) { | ||
343 | if (!clock_frequency_present) { | 359 | if (!clock_frequency_present) { |
344 | dev_err(&pdev->dev, | 360 | dev_err(&pdev->dev, |
345 | "Missing required parameter 'opencores,ip-clock-frequency'\n"); | 361 | "Missing required parameter 'opencores,ip-clock-frequency'\n"); |
@@ -477,6 +493,9 @@ static int ocores_i2c_remove(struct platform_device *pdev) | |||
477 | /* remove adapter & data */ | 493 | /* remove adapter & data */ |
478 | i2c_del_adapter(&i2c->adap); | 494 | i2c_del_adapter(&i2c->adap); |
479 | 495 | ||
496 | if (!IS_ERR(i2c->clk)) | ||
497 | clk_disable_unprepare(i2c->clk); | ||
498 | |||
480 | return 0; | 499 | return 0; |
481 | } | 500 | } |
482 | 501 | ||
@@ -489,6 +508,8 @@ static int ocores_i2c_suspend(struct device *dev) | |||
489 | /* make sure the device is disabled */ | 508 | /* make sure the device is disabled */ |
490 | oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); | 509 | oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); |
491 | 510 | ||
511 | if (!IS_ERR(i2c->clk)) | ||
512 | clk_disable_unprepare(i2c->clk); | ||
492 | return 0; | 513 | return 0; |
493 | } | 514 | } |
494 | 515 | ||
@@ -496,6 +517,16 @@ static int ocores_i2c_resume(struct device *dev) | |||
496 | { | 517 | { |
497 | struct ocores_i2c *i2c = dev_get_drvdata(dev); | 518 | struct ocores_i2c *i2c = dev_get_drvdata(dev); |
498 | 519 | ||
520 | if (!IS_ERR(i2c->clk)) { | ||
521 | int ret = clk_prepare_enable(i2c->clk); | ||
522 | |||
523 | if (ret) { | ||
524 | dev_err(dev, | ||
525 | "clk_prepare_enable failed: %d\n", ret); | ||
526 | return ret; | ||
527 | } | ||
528 | i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; | ||
529 | } | ||
499 | return ocores_init(dev, i2c); | 530 | return ocores_init(dev, i2c); |
500 | } | 531 | } |
501 | 532 | ||