diff options
| -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 | ||
