1 /* 2 * linux/arch/arm/common/amba.c 3 * 4 * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 #include <linux/module.h> 11 #include <linux/init.h> 12 #include <linux/device.h> 13 #include <linux/string.h> 14 #include <linux/slab.h> 15 #include <linux/amba/bus.h> 16 17 #include <asm/io.h> 18 #include <asm/sizes.h> 19 20 #define to_amba_device(d) container_of(d, struct amba_device, dev) 21 #define to_amba_driver(d) container_of(d, struct amba_driver, drv) 22 23 static struct amba_id * 24 amba_lookup(struct amba_id *table, struct amba_device *dev) 25 { 26 int ret = 0; 27 28 while (table->mask) { 29 ret = (dev->periphid & table->mask) == table->id; 30 if (ret) 31 break; 32 table++; 33 } 34 35 return ret ? table : NULL; 36 } 37 38 static int amba_match(struct device *dev, struct device_driver *drv) 39 { 40 struct amba_device *pcdev = to_amba_device(dev); 41 struct amba_driver *pcdrv = to_amba_driver(drv); 42 43 return amba_lookup(pcdrv->id_table, pcdev) != NULL; 44 } 45 46 #ifdef CONFIG_HOTPLUG 47 static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) 48 { 49 struct amba_device *pcdev = to_amba_device(dev); 50 int retval = 0; 51 52 retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); 53 return retval; 54 } 55 #else 56 #define amba_uevent NULL 57 #endif 58 59 static int amba_suspend(struct device *dev, pm_message_t state) 60 { 61 struct amba_driver *drv = to_amba_driver(dev->driver); 62 int ret = 0; 63 64 if (dev->driver && drv->suspend) 65 ret = drv->suspend(to_amba_device(dev), state); 66 return ret; 67 } 68 69 static int amba_resume(struct device *dev) 70 { 71 struct amba_driver *drv = to_amba_driver(dev->driver); 72 int ret = 0; 73 74 if (dev->driver && drv->resume) 75 ret = drv->resume(to_amba_device(dev)); 76 return ret; 77 } 78 79 #define amba_attr_func(name,fmt,arg...) \ 80 static ssize_t name##_show(struct device *_dev, \ 81 struct device_attribute *attr, char *buf) \ 82 { \ 83 struct amba_device *dev = to_amba_device(_dev); \ 84 return sprintf(buf, fmt, arg); \ 85 } 86 87 #define amba_attr(name,fmt,arg...) \ 88 amba_attr_func(name,fmt,arg) \ 89 static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL) 90 91 amba_attr_func(id, "%08x\n", dev->periphid); 92 amba_attr(irq0, "%u\n", dev->irq[0]); 93 amba_attr(irq1, "%u\n", dev->irq[1]); 94 amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", 95 (unsigned long long)dev->res.start, (unsigned long long)dev->res.end, 96 dev->res.flags); 97 98 static struct device_attribute amba_dev_attrs[] = { 99 __ATTR_RO(id), 100 __ATTR_RO(resource), 101 __ATTR_NULL, 102 }; 103 104 /* 105 * Primecells are part of the Advanced Microcontroller Bus Architecture, 106 * so we call the bus "amba". 107 */ 108 static struct bus_type amba_bustype = { 109 .name = "amba", 110 .dev_attrs = amba_dev_attrs, 111 .match = amba_match, 112 .uevent = amba_uevent, 113 .suspend = amba_suspend, 114 .resume = amba_resume, 115 }; 116 117 static int __init amba_init(void) 118 { 119 return bus_register(&amba_bustype); 120 } 121 122 postcore_initcall(amba_init); 123 124 /* 125 * These are the device model conversion veneers; they convert the 126 * device model structures to our more specific structures. 127 */ 128 static int amba_probe(struct device *dev) 129 { 130 struct amba_device *pcdev = to_amba_device(dev); 131 struct amba_driver *pcdrv = to_amba_driver(dev->driver); 132 struct amba_id *id; 133 134 id = amba_lookup(pcdrv->id_table, pcdev); 135 136 return pcdrv->probe(pcdev, id); 137 } 138 139 static int amba_remove(struct device *dev) 140 { 141 struct amba_driver *drv = to_amba_driver(dev->driver); 142 return drv->remove(to_amba_device(dev)); 143 } 144 145 static void amba_shutdown(struct device *dev) 146 { 147 struct amba_driver *drv = to_amba_driver(dev->driver); 148 drv->shutdown(to_amba_device(dev)); 149 } 150 151 /** 152 * amba_driver_register - register an AMBA device driver 153 * @drv: amba device driver structure 154 * 155 * Register an AMBA device driver with the Linux device model 156 * core. If devices pre-exist, the drivers probe function will 157 * be called. 158 */ 159 int amba_driver_register(struct amba_driver *drv) 160 { 161 drv->drv.bus = &amba_bustype; 162 163 #define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn 164 SETFN(probe); 165 SETFN(remove); 166 SETFN(shutdown); 167 168 return driver_register(&drv->drv); 169 } 170 171 /** 172 * amba_driver_unregister - remove an AMBA device driver 173 * @drv: AMBA device driver structure to remove 174 * 175 * Unregister an AMBA device driver from the Linux device 176 * model. The device model will call the drivers remove function 177 * for each device the device driver is currently handling. 178 */ 179 void amba_driver_unregister(struct amba_driver *drv) 180 { 181 driver_unregister(&drv->drv); 182 } 183 184 185 static void amba_device_release(struct device *dev) 186 { 187 struct amba_device *d = to_amba_device(dev); 188 189 if (d->res.parent) 190 release_resource(&d->res); 191 kfree(d); 192 } 193 194 /** 195 * amba_device_register - register an AMBA device 196 * @dev: AMBA device to register 197 * @parent: parent memory resource 198 * 199 * Setup the AMBA device, reading the cell ID if present. 200 * Claim the resource, and register the AMBA device with 201 * the Linux device manager. 202 */ 203 int amba_device_register(struct amba_device *dev, struct resource *parent) 204 { 205 u32 pid, cid; 206 void __iomem *tmp; 207 int i, ret; 208 209 dev->dev.release = amba_device_release; 210 dev->dev.bus = &amba_bustype; 211 dev->dev.dma_mask = &dev->dma_mask; 212 dev->res.name = dev->dev.bus_id; 213 214 if (!dev->dev.coherent_dma_mask && dev->dma_mask) 215 dev_warn(&dev->dev, "coherent dma mask is unset\n"); 216 217 ret = request_resource(parent, &dev->res); 218 if (ret) 219 goto err_out; 220 221 tmp = ioremap(dev->res.start, SZ_4K); 222 if (!tmp) { 223 ret = -ENOMEM; 224 goto err_release; 225 } 226 227 for (pid = 0, i = 0; i < 4; i++) 228 pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8); 229 for (cid = 0, i = 0; i < 4; i++) 230 cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8); 231 232 iounmap(tmp); 233 234 if (cid == 0xb105f00d) 235 dev->periphid = pid; 236 237 if (!dev->periphid) { 238 ret = -ENODEV; 239 goto err_release; 240 } 241 242 ret = device_register(&dev->dev); 243 if (ret) 244 goto err_release; 245 246 if (dev->irq[0] != NO_IRQ) 247 ret = device_create_file(&dev->dev, &dev_attr_irq0); 248 if (ret == 0 && dev->irq[1] != NO_IRQ) 249 ret = device_create_file(&dev->dev, &dev_attr_irq1); 250 if (ret == 0) 251 return ret; 252 253 device_unregister(&dev->dev); 254 255 err_release: 256 release_resource(&dev->res); 257 err_out: 258 return ret; 259 } 260 261 /** 262 * amba_device_unregister - unregister an AMBA device 263 * @dev: AMBA device to remove 264 * 265 * Remove the specified AMBA device from the Linux device 266 * manager. All files associated with this object will be 267 * destroyed, and device drivers notified that the device has 268 * been removed. The AMBA device's resources including 269 * the amba_device structure will be freed once all 270 * references to it have been dropped. 271 */ 272 void amba_device_unregister(struct amba_device *dev) 273 { 274 device_unregister(&dev->dev); 275 } 276 277 278 struct find_data { 279 struct amba_device *dev; 280 struct device *parent; 281 const char *busid; 282 unsigned int id; 283 unsigned int mask; 284 }; 285 286 static int amba_find_match(struct device *dev, void *data) 287 { 288 struct find_data *d = data; 289 struct amba_device *pcdev = to_amba_device(dev); 290 int r; 291 292 r = (pcdev->periphid & d->mask) == d->id; 293 if (d->parent) 294 r &= d->parent == dev->parent; 295 if (d->busid) 296 r &= strcmp(dev->bus_id, d->busid) == 0; 297 298 if (r) { 299 get_device(dev); 300 d->dev = pcdev; 301 } 302 303 return r; 304 } 305 306 /** 307 * amba_find_device - locate an AMBA device given a bus id 308 * @busid: bus id for device (or NULL) 309 * @parent: parent device (or NULL) 310 * @id: peripheral ID (or 0) 311 * @mask: peripheral ID mask (or 0) 312 * 313 * Return the AMBA device corresponding to the supplied parameters. 314 * If no device matches, returns NULL. 315 * 316 * NOTE: When a valid device is found, its refcount is 317 * incremented, and must be decremented before the returned 318 * reference. 319 */ 320 struct amba_device * 321 amba_find_device(const char *busid, struct device *parent, unsigned int id, 322 unsigned int mask) 323 { 324 struct find_data data; 325 326 data.dev = NULL; 327 data.parent = parent; 328 data.busid = busid; 329 data.id = id; 330 data.mask = mask; 331 332 bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); 333 334 return data.dev; 335 } 336 337 /** 338 * amba_request_regions - request all mem regions associated with device 339 * @dev: amba_device structure for device 340 * @name: name, or NULL to use driver name 341 */ 342 int amba_request_regions(struct amba_device *dev, const char *name) 343 { 344 int ret = 0; 345 346 if (!name) 347 name = dev->dev.driver->name; 348 349 if (!request_mem_region(dev->res.start, SZ_4K, name)) 350 ret = -EBUSY; 351 352 return ret; 353 } 354 355 /** 356 * amba_release_regions - release mem regions assoicated with device 357 * @dev: amba_device structure for device 358 * 359 * Release regions claimed by a successful call to amba_request_regions. 360 */ 361 void amba_release_regions(struct amba_device *dev) 362 { 363 release_mem_region(dev->res.start, SZ_4K); 364 } 365 366 EXPORT_SYMBOL(amba_driver_register); 367 EXPORT_SYMBOL(amba_driver_unregister); 368 EXPORT_SYMBOL(amba_device_register); 369 EXPORT_SYMBOL(amba_device_unregister); 370 EXPORT_SYMBOL(amba_find_device); 371 EXPORT_SYMBOL(amba_request_regions); 372 EXPORT_SYMBOL(amba_release_regions); 373