Blame view

arch/arm/plat-omap/i2c.c 7 KB
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
1
2
3
4
5
6
7
  /*
   * linux/arch/arm/plat-omap/i2c.c
   *
   * Helper module for board specific I2C bus registration
   *
   * Copyright (C) 2007 Nokia Corporation.
   *
ddf25dfe3   Jarkko Nikula   ARM: OMAP: Update...
8
   * Contact: Jarkko Nikula <jhnikula@gmail.com>
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * version 2 as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA
   *
   */
  
  #include <linux/kernel.h>
  #include <linux/platform_device.h>
  #include <linux/i2c.h>
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
29
  #include <linux/i2c-omap.h>
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
30
31
32
  #include <linux/slab.h>
  #include <linux/err.h>
  #include <linux/clk.h>
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
33

80b02c172   Russell King   [ARM] fix AT91, d...
34
  #include <mach/irqs.h>
ce491cf85   Tony Lindgren   omap: headers: Mo...
35
  #include <plat/mux.h>
9833eff3d   Jarkko Nikula   omap: i2c: Fix mu...
36
  #include <plat/i2c.h>
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
37
  #include <plat/omap-pm.h>
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
38
  #include <plat/omap_device.h>
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
39
40
41
  
  #define OMAP_I2C_SIZE		0x3f
  #define OMAP1_I2C_BASE		0xfffb3800
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
42

f7bb0d9ab   Benoit Cousson   I2C: i2c-omap: Ch...
43
  static const char name[] = "omap_i2c";
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  
  #define I2C_RESOURCE_BUILDER(base, irq)			\
  	{						\
  		.start	= (base),			\
  		.end	= (base) + OMAP_I2C_SIZE,	\
  		.flags	= IORESOURCE_MEM,		\
  	},						\
  	{						\
  		.start	= (irq),			\
  		.flags	= IORESOURCE_IRQ,		\
  	},
  
  static struct resource i2c_resources[][2] = {
  	{ I2C_RESOURCE_BUILDER(0, 0) },
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
58
59
60
61
62
63
64
65
66
67
68
69
  };
  
  #define I2C_DEV_BUILDER(bus_id, res, data)		\
  	{						\
  		.id	= (bus_id),			\
  		.name	= name,				\
  		.num_resources	= ARRAY_SIZE(res),	\
  		.resource	= (res),		\
  		.dev		= {			\
  			.platform_data	= (data),	\
  		},					\
  	}
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
70
71
72
  #define MAX_OMAP_I2C_HWMOD_NAME_LEN	16
  #define OMAP_I2C_MAX_CONTROLLERS 4
  static struct omap_i2c_bus_platform_data i2c_pdata[OMAP_I2C_MAX_CONTROLLERS];
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
73
  static struct platform_device omap_i2c_devices[] = {
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
74
  	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
75
  };
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
76
  #define OMAP_I2C_CMDLINE_SETUP	(BIT(31))
3a853fb93   Jarkko Nikula   ARM: OMAP: Add co...
77
78
79
80
81
82
83
84
85
86
  static int __init omap_i2c_nr_ports(void)
  {
  	int ports = 0;
  
  	if (cpu_class_is_omap1())
  		ports = 1;
  	else if (cpu_is_omap24xx())
  		ports = 2;
  	else if (cpu_is_omap34xx())
  		ports = 3;
6daa642d9   Tony Lindgren   omap4: Add suppor...
87
88
  	else if (cpu_is_omap44xx())
  		ports = 4;
3a853fb93   Jarkko Nikula   ARM: OMAP: Add co...
89
90
91
  
  	return ports;
  }
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
92
  static inline int omap1_i2c_add_bus(int bus_id)
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
93
  {
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
94
95
  	struct platform_device *pdev;
  	struct omap_i2c_bus_platform_data *pdata;
00b4ade1f   Paul Walmsley   OMAP1: I2C: fix d...
96
  	struct resource *res;
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
97

b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
98
  	omap1_i2c_mux_pins(bus_id);
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
99
  	pdev = &omap_i2c_devices[bus_id - 1];
00b4ade1f   Paul Walmsley   OMAP1: I2C: fix d...
100
101
102
103
  	res = pdev->resource;
  	res[0].start = OMAP1_I2C_BASE;
  	res[0].end = res[0].start + OMAP_I2C_SIZE;
  	res[1].start = INT_I2C;
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
104
  	pdata = &i2c_pdata[bus_id - 1];
67b90c672   Andy Green   I2C: OMAP1: set I...
105
106
  	/* all OMAP1 have IP version 1 register set */
  	pdata->rev = OMAP_I2C_IP_VERSION_1;
8e286f5a2   Andy Green   I2C: OMAP1: set i...
107
108
109
110
111
112
113
114
115
116
117
118
  	/* all OMAP1 I2C are implemented like this */
  	pdata->flags = OMAP_I2C_FLAG_NO_FIFO |
  		       OMAP_I2C_FLAG_SIMPLE_CLOCK |
  		       OMAP_I2C_FLAG_16BIT_DATA_REG |
  		       OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK;
  
  	/* how the cpu bus is wired up differs for 7xx only */
  
  	if (cpu_is_omap7xx())
  		pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_1;
  	else
  		pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2;
b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
119
120
  	return platform_device_register(pdev);
  }
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
121

790a26f65   Felipe Balbi   arm: omap: i2c: f...
122
  #ifdef CONFIG_ARCH_OMAP2PLUS
564889c1c   Paul Walmsley   OMAP: PM constrai...
123
124
125
126
127
128
129
130
131
  /*
   * XXX This function is a temporary compatibility wrapper - only
   * needed until the I2C driver can be converted to call
   * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
   */
  static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
  {
  	omap_pm_set_max_mpu_wakeup_lat(dev, t);
  }
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
132
133
134
135
  static inline int omap2_i2c_add_bus(int bus_id)
  {
  	int l;
  	struct omap_hwmod *oh;
3528c58eb   Kevin Hilman   OMAP: omap_device...
136
  	struct platform_device *pdev;
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
137
138
  	char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN];
  	struct omap_i2c_bus_platform_data *pdata;
029a1e73c   Andy Green   I2C: OMAP2+: Pass...
139
  	struct omap_i2c_dev_attr *dev_attr;
b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
140

4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
141
  	omap2_i2c_mux_pins(bus_id);
b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
142

4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
143
144
145
146
147
148
149
150
151
  	l = snprintf(oh_name, MAX_OMAP_I2C_HWMOD_NAME_LEN, "i2c%d", bus_id);
  	WARN(l >= MAX_OMAP_I2C_HWMOD_NAME_LEN,
  		"String buffer overflow in I2C%d device setup
  ", bus_id);
  	oh = omap_hwmod_lookup(oh_name);
  	if (!oh) {
  			pr_err("Could not look up %s
  ", oh_name);
  			return -EEXIST;
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
152
  	}
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
153
  	pdata = &i2c_pdata[bus_id - 1];
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
154
  	/*
d177e5ddb   Andy Green   I2C: OMAP2+: Pass...
155
  	 * pass the hwmod class's CPU-specific knowledge of I2C IP revision in
029a1e73c   Andy Green   I2C: OMAP2+: Pass...
156
157
  	 * use, and functionality implementation flags, up to the OMAP I2C
  	 * driver via platform data
d177e5ddb   Andy Green   I2C: OMAP2+: Pass...
158
159
  	 */
  	pdata->rev = oh->class->rev;
029a1e73c   Andy Green   I2C: OMAP2+: Pass...
160
161
  	dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
  	pdata->flags = dev_attr->flags;
d177e5ddb   Andy Green   I2C: OMAP2+: Pass...
162
  	/*
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
163
164
165
166
  	 * When waiting for completion of a i2c transfer, we need to
  	 * set a wake up latency constraint for the MPU. This is to
  	 * ensure quick enough wakeup from idle, when transfer
  	 * completes.
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
167
  	 * Only omap3 has support for constraints
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
168
  	 */
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
169
170
  	if (cpu_is_omap34xx())
  		pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
3528c58eb   Kevin Hilman   OMAP: omap_device...
171
  	pdev = omap_device_build(name, bus_id, oh, pdata,
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
172
  			sizeof(struct omap_i2c_bus_platform_data),
f718e2c03   Benoit Cousson   ARM: OMAP2+: devi...
173
  			NULL, 0, 0);
3528c58eb   Kevin Hilman   OMAP: omap_device...
174
175
  	WARN(IS_ERR(pdev), "Could not build omap_device for %s
  ", name);
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
176

af504e5d3   Laurent Pinchart   ARM: OMAP: I2C: F...
177
  	return PTR_RET(pdev);
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
178
  }
be40f7a3d   Tony Lindgren   omap: Fix undefin...
179
180
181
182
183
184
  #else
  static inline int omap2_i2c_add_bus(int bus_id)
  {
  	return 0;
  }
  #endif
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
185

b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
186
187
  static int __init omap_i2c_add_bus(int bus_id)
  {
b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
188
  	if (cpu_class_is_omap1())
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
189
  		return omap1_i2c_add_bus(bus_id);
b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
190
  	else
4d17aeb1c   Paul Walmsley   OMAP: I2C: split ...
191
  		return omap2_i2c_add_bus(bus_id);
b32dd41ed   Tony Lindgren   omap: Fix i2c pla...
192
  }
3a853fb93   Jarkko Nikula   ARM: OMAP: Add co...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  /**
   * omap_i2c_bus_setup - Process command line options for the I2C bus speed
   * @str: String of options
   *
   * This function allow to override the default I2C bus speed for given I2C
   * bus with a command line option.
   *
   * Format: i2c_bus=bus_id,clkrate (in kHz)
   *
   * Returns 1 on success, 0 otherwise.
   */
  static int __init omap_i2c_bus_setup(char *str)
  {
  	int ports;
  	int ints[3];
  
  	ports = omap_i2c_nr_ports();
  	get_options(str, 3, ints);
  	if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
  		return 0;
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
213
214
  	i2c_pdata[ints[1] - 1].clkrate = ints[2];
  	i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
3a853fb93   Jarkko Nikula   ARM: OMAP: Add co...
215
216
217
218
  
  	return 1;
  }
  __setup("i2c_bus=", omap_i2c_bus_setup);
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
219
220
221
222
223
224
225
  /*
   * Register busses defined in command line but that are not registered with
   * omap_register_i2c_bus from board initialization code.
   */
  static int __init omap_register_i2c_bus_cmdline(void)
  {
  	int i, err = 0;
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
226
227
228
  	for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
  		if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
  			i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
229
230
231
232
233
234
235
236
237
  			err = omap_i2c_add_bus(i + 1);
  			if (err)
  				goto out;
  		}
  
  out:
  	return err;
  }
  subsys_initcall(omap_register_i2c_bus_cmdline);
d4c58bf45   Jarkko Nikula   ARM: OMAP: Add do...
238
  /**
9833eff3d   Jarkko Nikula   omap: i2c: Fix mu...
239
   * omap_register_i2c_bus - register I2C bus with device descriptors
d4c58bf45   Jarkko Nikula   ARM: OMAP: Add do...
240
241
242
243
244
245
246
   * @bus_id: bus id counting from number 1
   * @clkrate: clock rate of the bus in kHz
   * @info: pointer into I2C device descriptor table or NULL
   * @len: number of descriptors in the table
   *
   * Returns 0 on success or an error code.
   */
9833eff3d   Jarkko Nikula   omap: i2c: Fix mu...
247
  int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
248
249
250
  			  struct i2c_board_info const *info,
  			  unsigned len)
  {
3a853fb93   Jarkko Nikula   ARM: OMAP: Add co...
251
  	int err;
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
252

3a853fb93   Jarkko Nikula   ARM: OMAP: Add co...
253
  	BUG_ON(bus_id < 1 || bus_id > omap_i2c_nr_ports());
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
254
255
256
257
258
259
  
  	if (info) {
  		err = i2c_register_board_info(bus_id, info, len);
  		if (err)
  			return err;
  	}
20c9d2c4a   Kalle Jokiniemi   i2c-omap: add mpu...
260
261
262
263
  	if (!i2c_pdata[bus_id - 1].clkrate)
  		i2c_pdata[bus_id - 1].clkrate = clkrate;
  
  	i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
264

7954763bb   Jarkko Nikula   ARM: OMAP: Add me...
265
  	return omap_i2c_add_bus(bus_id);
85d05fb3f   Jarkko Nikula   ARM: OMAP: Add he...
266
  }