diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-powermac.c | 98 |
1 files changed, 71 insertions, 27 deletions
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 7b397c6f607e..31c47e18d83c 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c | |||
@@ -227,6 +227,72 @@ static int __devexit i2c_powermac_remove(struct platform_device *dev) | |||
227 | return 0; | 227 | return 0; |
228 | } | 228 | } |
229 | 229 | ||
230 | static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap, | ||
231 | struct pmac_i2c_bus *bus) | ||
232 | { | ||
233 | struct i2c_client *newdev; | ||
234 | struct device_node *node; | ||
235 | |||
236 | for_each_child_of_node(adap->dev.of_node, node) { | ||
237 | struct i2c_board_info info = {}; | ||
238 | struct dev_archdata dev_ad = {}; | ||
239 | const __be32 *reg; | ||
240 | char tmp[16]; | ||
241 | u32 addr; | ||
242 | int len; | ||
243 | |||
244 | /* Get address & channel */ | ||
245 | reg = of_get_property(node, "reg", &len); | ||
246 | if (!reg || (len < sizeof(int))) { | ||
247 | dev_err(&adap->dev, "i2c-powermac: invalid reg on %s\n", | ||
248 | node->full_name); | ||
249 | continue; | ||
250 | } | ||
251 | addr = be32_to_cpup(reg); | ||
252 | |||
253 | /* Multibus setup, check channel */ | ||
254 | if (!pmac_i2c_match_adapter(node, adap)) | ||
255 | continue; | ||
256 | |||
257 | dev_dbg(&adap->dev, "i2c-powermac: register %s\n", | ||
258 | node->full_name); | ||
259 | |||
260 | /* Make up a modalias. Note: we to _NOT_ want the standard | ||
261 | * i2c drivers to match with any of our powermac stuff | ||
262 | * unless they have been specifically modified to handle | ||
263 | * it on a case by case basis. For example, for thermal | ||
264 | * control, things like lm75 etc... shall match with their | ||
265 | * corresponding windfarm drivers, _NOT_ the generic ones, | ||
266 | * so we force a prefix of AAPL, onto the modalias to | ||
267 | * make that happen | ||
268 | */ | ||
269 | if (of_modalias_node(node, tmp, sizeof(tmp)) < 0) { | ||
270 | dev_err(&adap->dev, "i2c-powermac: modalias failure" | ||
271 | " on %s\n", node->full_name); | ||
272 | continue; | ||
273 | } | ||
274 | snprintf(info.type, sizeof(info.type), "MAC,%s", tmp); | ||
275 | |||
276 | /* Fill out the rest of the info structure */ | ||
277 | info.addr = (addr & 0xff) >> 1; | ||
278 | info.irq = irq_of_parse_and_map(node, 0); | ||
279 | info.of_node = of_node_get(node); | ||
280 | info.archdata = &dev_ad; | ||
281 | |||
282 | newdev = i2c_new_device(adap, &info); | ||
283 | if (!newdev) { | ||
284 | dev_err(&adap->dev, "i2c-powermac: Failure to register" | ||
285 | " %s\n", node->full_name); | ||
286 | of_node_put(node); | ||
287 | /* We do not dispose of the interrupt mapping on | ||
288 | * purpose. It's not necessary (interrupt cannot be | ||
289 | * re-used) and somebody else might have grabbed it | ||
290 | * via direct DT lookup so let's not bother | ||
291 | */ | ||
292 | continue; | ||
293 | } | ||
294 | } | ||
295 | } | ||
230 | 296 | ||
231 | static int __devinit i2c_powermac_probe(struct platform_device *dev) | 297 | static int __devinit i2c_powermac_probe(struct platform_device *dev) |
232 | { | 298 | { |
@@ -272,6 +338,7 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) | |||
272 | adapter->algo = &i2c_powermac_algorithm; | 338 | adapter->algo = &i2c_powermac_algorithm; |
273 | i2c_set_adapdata(adapter, bus); | 339 | i2c_set_adapdata(adapter, bus); |
274 | adapter->dev.parent = &dev->dev; | 340 | adapter->dev.parent = &dev->dev; |
341 | adapter->dev.of_node = dev->dev.of_node; | ||
275 | rc = i2c_add_adapter(adapter); | 342 | rc = i2c_add_adapter(adapter); |
276 | if (rc) { | 343 | if (rc) { |
277 | printk(KERN_ERR "i2c-powermac: Adapter %s registration " | 344 | printk(KERN_ERR "i2c-powermac: Adapter %s registration " |
@@ -281,33 +348,10 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) | |||
281 | 348 | ||
282 | printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name); | 349 | printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name); |
283 | 350 | ||
284 | if (!strncmp(basename, "uni-n", 5)) { | 351 | /* Cannot use of_i2c_register_devices() due to Apple device-tree |
285 | struct device_node *np; | 352 | * funkyness |
286 | const u32 *prop; | 353 | */ |
287 | struct i2c_board_info info; | 354 | i2c_powermac_register_devices(adapter, bus); |
288 | |||
289 | /* Instantiate I2C motion sensor if present */ | ||
290 | np = of_find_node_by_name(NULL, "accelerometer"); | ||
291 | if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") && | ||
292 | (prop = of_get_property(np, "reg", NULL))) { | ||
293 | int i2c_bus; | ||
294 | const char *tmp_bus; | ||
295 | |||
296 | /* look for bus either using "reg" or by path */ | ||
297 | tmp_bus = strstr(np->full_name, "/i2c-bus@"); | ||
298 | if (tmp_bus) | ||
299 | i2c_bus = *(tmp_bus + 9) - '0'; | ||
300 | else | ||
301 | i2c_bus = ((*prop) >> 8) & 0x0f; | ||
302 | |||
303 | if (pmac_i2c_get_channel(bus) == i2c_bus) { | ||
304 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
305 | info.addr = ((*prop) & 0xff) >> 1; | ||
306 | strlcpy(info.type, "ams", I2C_NAME_SIZE); | ||
307 | i2c_new_device(adapter, &info); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | 355 | ||
312 | return rc; | 356 | return rc; |
313 | } | 357 | } |