diff options
author | Alexandre Belloni <alexandre.belloni@bootlin.com> | 2018-08-31 11:11:12 -0400 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2018-09-02 17:51:15 -0400 |
commit | 1bb39959623b438d6b7705abfd0538e8ef4f5f0f (patch) | |
tree | 0baa02df2f094bec970ed00bbbb2f3725d5a14d5 | |
parent | ffbc01bff2ef98430e4ab486b878f04fe7bb7c29 (diff) |
i2c: designware: add MSCC Ocelot support
The Microsemi Ocelot I2C controller is a designware IP. It also has a
second set of registers to allow tweaking SDA hold time and spike
filtering.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
[wsa: made one function static]
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 40 |
2 files changed, 43 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index f6cad20a86ff..5b550ab9a009 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h | |||
@@ -225,6 +225,7 @@ | |||
225 | struct dw_i2c_dev { | 225 | struct dw_i2c_dev { |
226 | struct device *dev; | 226 | struct device *dev; |
227 | void __iomem *base; | 227 | void __iomem *base; |
228 | void __iomem *ext; | ||
228 | struct completion cmd_complete; | 229 | struct completion cmd_complete; |
229 | struct clk *clk; | 230 | struct clk *clk; |
230 | struct reset_control *rst; | 231 | struct reset_control *rst; |
@@ -279,6 +280,8 @@ struct dw_i2c_dev { | |||
279 | #define ACCESS_INTR_MASK 0x00000004 | 280 | #define ACCESS_INTR_MASK 0x00000004 |
280 | 281 | ||
281 | #define MODEL_CHERRYTRAIL 0x00000100 | 282 | #define MODEL_CHERRYTRAIL 0x00000100 |
283 | #define MODEL_MSCC_OCELOT 0x00000200 | ||
284 | #define MODEL_MASK 0x00000f00 | ||
282 | 285 | ||
283 | u32 dw_readl(struct dw_i2c_dev *dev, int offset); | 286 | u32 dw_readl(struct dw_i2c_dev *dev, int offset); |
284 | void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); | 287 | void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); |
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 723892820e2b..a56af235e9a6 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c | |||
@@ -157,11 +157,48 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) | |||
157 | #endif | 157 | #endif |
158 | 158 | ||
159 | #ifdef CONFIG_OF | 159 | #ifdef CONFIG_OF |
160 | #define MSCC_ICPU_CFG_TWI_DELAY 0x0 | ||
161 | #define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0) | ||
162 | #define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4 | ||
163 | |||
164 | static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev) | ||
165 | { | ||
166 | writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE, | ||
167 | dev->ext + MSCC_ICPU_CFG_TWI_DELAY); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int dw_i2c_of_configure(struct platform_device *pdev) | ||
173 | { | ||
174 | struct dw_i2c_dev *dev = platform_get_drvdata(pdev); | ||
175 | struct resource *mem; | ||
176 | |||
177 | switch (dev->flags & MODEL_MASK) { | ||
178 | case MODEL_MSCC_OCELOT: | ||
179 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
180 | dev->ext = devm_ioremap_resource(&pdev->dev, mem); | ||
181 | if (!IS_ERR(dev->ext)) | ||
182 | dev->set_sda_hold_time = mscc_twi_set_sda_hold_time; | ||
183 | break; | ||
184 | default: | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
160 | static const struct of_device_id dw_i2c_of_match[] = { | 191 | static const struct of_device_id dw_i2c_of_match[] = { |
161 | { .compatible = "snps,designware-i2c", }, | 192 | { .compatible = "snps,designware-i2c", }, |
193 | { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT }, | ||
162 | {}, | 194 | {}, |
163 | }; | 195 | }; |
164 | MODULE_DEVICE_TABLE(of, dw_i2c_of_match); | 196 | MODULE_DEVICE_TABLE(of, dw_i2c_of_match); |
197 | #else | ||
198 | static inline int dw_i2c_of_configure(struct platform_device *pdev) | ||
199 | { | ||
200 | return -ENODEV; | ||
201 | } | ||
165 | #endif | 202 | #endif |
166 | 203 | ||
167 | static void i2c_dw_configure_master(struct dw_i2c_dev *dev) | 204 | static void i2c_dw_configure_master(struct dw_i2c_dev *dev) |
@@ -296,6 +333,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | |||
296 | 333 | ||
297 | dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev); | 334 | dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev); |
298 | 335 | ||
336 | if (pdev->dev.of_node) | ||
337 | dw_i2c_of_configure(pdev); | ||
338 | |||
299 | if (has_acpi_companion(&pdev->dev)) | 339 | if (has_acpi_companion(&pdev->dev)) |
300 | dw_i2c_acpi_configure(pdev); | 340 | dw_i2c_acpi_configure(pdev); |
301 | 341 | ||