Skip to content

Commit ad7d142

Browse files
jue89Wolfram Sang
authored andcommitted
i2c: at91: split driver into core and master file
The single file i2c-at91.c has been split into core code (i2c-at91-core.c) and master mode specific code (i2c-at91-master.c). This should enhance maintainability and reduce ifdeffery for slave mode related code. The code itself hasn't been touched. Shared functions only had to be made non-static. Furthermore, includes have been cleaned up. Signed-off-by: Juergen Fitschen <me@jue.yt> [ludovic.desroches@microchip.com: fix checkpatch errors and use SPDX] Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
1 parent 07345ab commit ad7d142

File tree

5 files changed

+524
-469
lines changed

5 files changed

+524
-469
lines changed

MAINTAINERS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10102,7 +10102,8 @@ MICROCHIP I2C DRIVER
1010210102
M: Ludovic Desroches <ludovic.desroches@microchip.com>
1010310103
L: linux-i2c@vger.kernel.org
1010410104
S: Supported
10105-
F: drivers/i2c/busses/i2c-at91.c
10105+
F: drivers/i2c/busses/i2c-at91.h
10106+
F: drivers/i2c/busses/i2c-at91-*.c
1010610107

1010710108
MICROCHIP ISC DRIVER
1010810109
M: Eugen Hristev <eugen.hristev@microchip.com>

drivers/i2c/busses/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
3535
obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o
3636
obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
3737
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
38+
i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o
3839
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
3940
obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
4041
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o

drivers/i2c/busses/i2c-at91-core.c

Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
4+
*
5+
* Copyright (C) 2011 Weinmann Medical GmbH
6+
* Author: Nikolaus Voss <n.voss@weinmann.de>
7+
*
8+
* Evolved from original work by:
9+
* Copyright (C) 2004 Rick Bronson
10+
* Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
11+
*
12+
* Borrowed heavily from original work by:
13+
* Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
14+
*/
15+
16+
#include <linux/clk.h>
17+
#include <linux/err.h>
18+
#include <linux/i2c.h>
19+
#include <linux/io.h>
20+
#include <linux/module.h>
21+
#include <linux/of.h>
22+
#include <linux/of_device.h>
23+
#include <linux/platform_device.h>
24+
#include <linux/pm_runtime.h>
25+
#include <linux/pinctrl/consumer.h>
26+
27+
#include "i2c-at91.h"
28+
29+
unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
30+
{
31+
return readl_relaxed(dev->base + reg);
32+
}
33+
34+
void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
35+
{
36+
writel_relaxed(val, dev->base + reg);
37+
}
38+
39+
void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
40+
{
41+
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK);
42+
}
43+
44+
void at91_twi_irq_save(struct at91_twi_dev *dev)
45+
{
46+
dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK;
47+
at91_disable_twi_interrupts(dev);
48+
}
49+
50+
void at91_twi_irq_restore(struct at91_twi_dev *dev)
51+
{
52+
at91_twi_write(dev, AT91_TWI_IER, dev->imr);
53+
}
54+
55+
void at91_init_twi_bus(struct at91_twi_dev *dev)
56+
{
57+
at91_disable_twi_interrupts(dev);
58+
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
59+
60+
at91_init_twi_bus_master(dev);
61+
}
62+
63+
static struct at91_twi_pdata at91rm9200_config = {
64+
.clk_max_div = 5,
65+
.clk_offset = 3,
66+
.has_unre_flag = true,
67+
.has_alt_cmd = false,
68+
.has_hold_field = false,
69+
};
70+
71+
static struct at91_twi_pdata at91sam9261_config = {
72+
.clk_max_div = 5,
73+
.clk_offset = 4,
74+
.has_unre_flag = false,
75+
.has_alt_cmd = false,
76+
.has_hold_field = false,
77+
};
78+
79+
static struct at91_twi_pdata at91sam9260_config = {
80+
.clk_max_div = 7,
81+
.clk_offset = 4,
82+
.has_unre_flag = false,
83+
.has_alt_cmd = false,
84+
.has_hold_field = false,
85+
};
86+
87+
static struct at91_twi_pdata at91sam9g20_config = {
88+
.clk_max_div = 7,
89+
.clk_offset = 4,
90+
.has_unre_flag = false,
91+
.has_alt_cmd = false,
92+
.has_hold_field = false,
93+
};
94+
95+
static struct at91_twi_pdata at91sam9g10_config = {
96+
.clk_max_div = 7,
97+
.clk_offset = 4,
98+
.has_unre_flag = false,
99+
.has_alt_cmd = false,
100+
.has_hold_field = false,
101+
};
102+
103+
static const struct platform_device_id at91_twi_devtypes[] = {
104+
{
105+
.name = "i2c-at91rm9200",
106+
.driver_data = (unsigned long) &at91rm9200_config,
107+
}, {
108+
.name = "i2c-at91sam9261",
109+
.driver_data = (unsigned long) &at91sam9261_config,
110+
}, {
111+
.name = "i2c-at91sam9260",
112+
.driver_data = (unsigned long) &at91sam9260_config,
113+
}, {
114+
.name = "i2c-at91sam9g20",
115+
.driver_data = (unsigned long) &at91sam9g20_config,
116+
}, {
117+
.name = "i2c-at91sam9g10",
118+
.driver_data = (unsigned long) &at91sam9g10_config,
119+
}, {
120+
/* sentinel */
121+
}
122+
};
123+
124+
#if defined(CONFIG_OF)
125+
static struct at91_twi_pdata at91sam9x5_config = {
126+
.clk_max_div = 7,
127+
.clk_offset = 4,
128+
.has_unre_flag = false,
129+
.has_alt_cmd = false,
130+
.has_hold_field = false,
131+
};
132+
133+
static struct at91_twi_pdata sama5d4_config = {
134+
.clk_max_div = 7,
135+
.clk_offset = 4,
136+
.has_unre_flag = false,
137+
.has_alt_cmd = false,
138+
.has_hold_field = true,
139+
};
140+
141+
static struct at91_twi_pdata sama5d2_config = {
142+
.clk_max_div = 7,
143+
.clk_offset = 4,
144+
.has_unre_flag = true,
145+
.has_alt_cmd = true,
146+
.has_hold_field = true,
147+
};
148+
149+
static const struct of_device_id atmel_twi_dt_ids[] = {
150+
{
151+
.compatible = "atmel,at91rm9200-i2c",
152+
.data = &at91rm9200_config,
153+
}, {
154+
.compatible = "atmel,at91sam9260-i2c",
155+
.data = &at91sam9260_config,
156+
}, {
157+
.compatible = "atmel,at91sam9261-i2c",
158+
.data = &at91sam9261_config,
159+
}, {
160+
.compatible = "atmel,at91sam9g20-i2c",
161+
.data = &at91sam9g20_config,
162+
}, {
163+
.compatible = "atmel,at91sam9g10-i2c",
164+
.data = &at91sam9g10_config,
165+
}, {
166+
.compatible = "atmel,at91sam9x5-i2c",
167+
.data = &at91sam9x5_config,
168+
}, {
169+
.compatible = "atmel,sama5d4-i2c",
170+
.data = &sama5d4_config,
171+
}, {
172+
.compatible = "atmel,sama5d2-i2c",
173+
.data = &sama5d2_config,
174+
}, {
175+
/* sentinel */
176+
}
177+
};
178+
MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
179+
#endif
180+
181+
static struct at91_twi_pdata *at91_twi_get_driver_data(
182+
struct platform_device *pdev)
183+
{
184+
if (pdev->dev.of_node) {
185+
const struct of_device_id *match;
186+
match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
187+
if (!match)
188+
return NULL;
189+
return (struct at91_twi_pdata *)match->data;
190+
}
191+
return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
192+
}
193+
194+
static int at91_twi_probe(struct platform_device *pdev)
195+
{
196+
struct at91_twi_dev *dev;
197+
struct resource *mem;
198+
int rc;
199+
u32 phy_addr;
200+
201+
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
202+
if (!dev)
203+
return -ENOMEM;
204+
205+
dev->dev = &pdev->dev;
206+
207+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
208+
if (!mem)
209+
return -ENODEV;
210+
phy_addr = mem->start;
211+
212+
dev->pdata = at91_twi_get_driver_data(pdev);
213+
if (!dev->pdata)
214+
return -ENODEV;
215+
216+
dev->base = devm_ioremap_resource(&pdev->dev, mem);
217+
if (IS_ERR(dev->base))
218+
return PTR_ERR(dev->base);
219+
220+
dev->irq = platform_get_irq(pdev, 0);
221+
if (dev->irq < 0)
222+
return dev->irq;
223+
224+
platform_set_drvdata(pdev, dev);
225+
226+
dev->clk = devm_clk_get(dev->dev, NULL);
227+
if (IS_ERR(dev->clk)) {
228+
dev_err(dev->dev, "no clock defined\n");
229+
return -ENODEV;
230+
}
231+
clk_prepare_enable(dev->clk);
232+
233+
snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
234+
i2c_set_adapdata(&dev->adapter, dev);
235+
dev->adapter.owner = THIS_MODULE;
236+
dev->adapter.class = I2C_CLASS_DEPRECATED;
237+
dev->adapter.dev.parent = dev->dev;
238+
dev->adapter.nr = pdev->id;
239+
dev->adapter.timeout = AT91_I2C_TIMEOUT;
240+
dev->adapter.dev.of_node = pdev->dev.of_node;
241+
242+
rc = at91_twi_probe_master(pdev, phy_addr, dev);
243+
if (rc)
244+
return rc;
245+
246+
at91_init_twi_bus(dev);
247+
248+
pm_runtime_set_autosuspend_delay(dev->dev, AUTOSUSPEND_TIMEOUT);
249+
pm_runtime_use_autosuspend(dev->dev);
250+
pm_runtime_set_active(dev->dev);
251+
pm_runtime_enable(dev->dev);
252+
253+
rc = i2c_add_numbered_adapter(&dev->adapter);
254+
if (rc) {
255+
clk_disable_unprepare(dev->clk);
256+
257+
pm_runtime_disable(dev->dev);
258+
pm_runtime_set_suspended(dev->dev);
259+
260+
return rc;
261+
}
262+
263+
dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n",
264+
at91_twi_read(dev, AT91_TWI_VER));
265+
return 0;
266+
}
267+
268+
static int at91_twi_remove(struct platform_device *pdev)
269+
{
270+
struct at91_twi_dev *dev = platform_get_drvdata(pdev);
271+
272+
i2c_del_adapter(&dev->adapter);
273+
clk_disable_unprepare(dev->clk);
274+
275+
pm_runtime_disable(dev->dev);
276+
pm_runtime_set_suspended(dev->dev);
277+
278+
return 0;
279+
}
280+
281+
#ifdef CONFIG_PM
282+
283+
static int at91_twi_runtime_suspend(struct device *dev)
284+
{
285+
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
286+
287+
clk_disable_unprepare(twi_dev->clk);
288+
289+
pinctrl_pm_select_sleep_state(dev);
290+
291+
return 0;
292+
}
293+
294+
static int at91_twi_runtime_resume(struct device *dev)
295+
{
296+
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
297+
298+
pinctrl_pm_select_default_state(dev);
299+
300+
return clk_prepare_enable(twi_dev->clk);
301+
}
302+
303+
static int at91_twi_suspend_noirq(struct device *dev)
304+
{
305+
if (!pm_runtime_status_suspended(dev))
306+
at91_twi_runtime_suspend(dev);
307+
308+
return 0;
309+
}
310+
311+
static int at91_twi_resume_noirq(struct device *dev)
312+
{
313+
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
314+
int ret;
315+
316+
if (!pm_runtime_status_suspended(dev)) {
317+
ret = at91_twi_runtime_resume(dev);
318+
if (ret)
319+
return ret;
320+
}
321+
322+
pm_runtime_mark_last_busy(dev);
323+
pm_request_autosuspend(dev);
324+
325+
at91_init_twi_bus(twi_dev);
326+
327+
return 0;
328+
}
329+
330+
static const struct dev_pm_ops at91_twi_pm = {
331+
.suspend_noirq = at91_twi_suspend_noirq,
332+
.resume_noirq = at91_twi_resume_noirq,
333+
.runtime_suspend = at91_twi_runtime_suspend,
334+
.runtime_resume = at91_twi_runtime_resume,
335+
};
336+
337+
#define at91_twi_pm_ops (&at91_twi_pm)
338+
#else
339+
#define at91_twi_pm_ops NULL
340+
#endif
341+
342+
static struct platform_driver at91_twi_driver = {
343+
.probe = at91_twi_probe,
344+
.remove = at91_twi_remove,
345+
.id_table = at91_twi_devtypes,
346+
.driver = {
347+
.name = "at91_i2c",
348+
.of_match_table = of_match_ptr(atmel_twi_dt_ids),
349+
.pm = at91_twi_pm_ops,
350+
},
351+
};
352+
353+
static int __init at91_twi_init(void)
354+
{
355+
return platform_driver_register(&at91_twi_driver);
356+
}
357+
358+
static void __exit at91_twi_exit(void)
359+
{
360+
platform_driver_unregister(&at91_twi_driver);
361+
}
362+
363+
subsys_initcall(at91_twi_init);
364+
module_exit(at91_twi_exit);
365+
366+
MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
367+
MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
368+
MODULE_LICENSE("GPL");
369+
MODULE_ALIAS("platform:at91_i2c");

0 commit comments

Comments
 (0)