1 /* 2 * linux/drivers/mfd/mcp-core.c 3 * 4 * Copyright (C) 2001 Russell King 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 as published by 8 * the Free Software Foundation; either version 2 of the License. 9 * 10 * Generic MCP (Multimedia Communications Port) layer. All MCP locking 11 * is solely held within this file. 12 */ 13 #include <linux/module.h> 14 #include <linux/init.h> 15 #include <linux/errno.h> 16 #include <linux/smp.h> 17 #include <linux/device.h> 18 19 #include <asm/dma.h> 20 #include <asm/system.h> 21 22 #include "mcp.h" 23 24 #define to_mcp(d) container_of(d, struct mcp, attached_device) 25 #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) 26 27 static int mcp_bus_match(struct device *dev, struct device_driver *drv) 28 { 29 return 1; 30 } 31 32 static int mcp_bus_probe(struct device *dev) 33 { 34 struct mcp *mcp = to_mcp(dev); 35 struct mcp_driver *drv = to_mcp_driver(dev->driver); 36 37 return drv->probe(mcp); 38 } 39 40 static int mcp_bus_remove(struct device *dev) 41 { 42 struct mcp *mcp = to_mcp(dev); 43 struct mcp_driver *drv = to_mcp_driver(dev->driver); 44 45 drv->remove(mcp); 46 return 0; 47 } 48 49 static int mcp_bus_suspend(struct device *dev, pm_message_t state) 50 { 51 struct mcp *mcp = to_mcp(dev); 52 int ret = 0; 53 54 if (dev->driver) { 55 struct mcp_driver *drv = to_mcp_driver(dev->driver); 56 57 ret = drv->suspend(mcp, state); 58 } 59 return ret; 60 } 61 62 static int mcp_bus_resume(struct device *dev) 63 { 64 struct mcp *mcp = to_mcp(dev); 65 int ret = 0; 66 67 if (dev->driver) { 68 struct mcp_driver *drv = to_mcp_driver(dev->driver); 69 70 ret = drv->resume(mcp); 71 } 72 return ret; 73 } 74 75 static struct bus_type mcp_bus_type = { 76 .name = "mcp", 77 .match = mcp_bus_match, 78 .suspend = mcp_bus_suspend, 79 .resume = mcp_bus_resume, 80 }; 81 82 /** 83 * mcp_set_telecom_divisor - set the telecom divisor 84 * @mcp: MCP interface structure 85 * @div: SIB clock divisor 86 * 87 * Set the telecom divisor on the MCP interface. The resulting 88 * sample rate is SIBCLOCK/div. 89 */ 90 void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div) 91 { 92 spin_lock_irq(&mcp->lock); 93 mcp->ops->set_telecom_divisor(mcp, div); 94 spin_unlock_irq(&mcp->lock); 95 } 96 EXPORT_SYMBOL(mcp_set_telecom_divisor); 97 98 /** 99 * mcp_set_audio_divisor - set the audio divisor 100 * @mcp: MCP interface structure 101 * @div: SIB clock divisor 102 * 103 * Set the audio divisor on the MCP interface. 104 */ 105 void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div) 106 { 107 spin_lock_irq(&mcp->lock); 108 mcp->ops->set_audio_divisor(mcp, div); 109 spin_unlock_irq(&mcp->lock); 110 } 111 EXPORT_SYMBOL(mcp_set_audio_divisor); 112 113 /** 114 * mcp_reg_write - write a device register 115 * @mcp: MCP interface structure 116 * @reg: 4-bit register index 117 * @val: 16-bit data value 118 * 119 * Write a device register. The MCP interface must be enabled 120 * to prevent this function hanging. 121 */ 122 void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) 123 { 124 unsigned long flags; 125 126 spin_lock_irqsave(&mcp->lock, flags); 127 mcp->ops->reg_write(mcp, reg, val); 128 spin_unlock_irqrestore(&mcp->lock, flags); 129 } 130 EXPORT_SYMBOL(mcp_reg_write); 131 132 /** 133 * mcp_reg_read - read a device register 134 * @mcp: MCP interface structure 135 * @reg: 4-bit register index 136 * 137 * Read a device register and return its value. The MCP interface 138 * must be enabled to prevent this function hanging. 139 */ 140 unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) 141 { 142 unsigned long flags; 143 unsigned int val; 144 145 spin_lock_irqsave(&mcp->lock, flags); 146 val = mcp->ops->reg_read(mcp, reg); 147 spin_unlock_irqrestore(&mcp->lock, flags); 148 149 return val; 150 } 151 EXPORT_SYMBOL(mcp_reg_read); 152 153 /** 154 * mcp_enable - enable the MCP interface 155 * @mcp: MCP interface to enable 156 * 157 * Enable the MCP interface. Each call to mcp_enable will need 158 * a corresponding call to mcp_disable to disable the interface. 159 */ 160 void mcp_enable(struct mcp *mcp) 161 { 162 spin_lock_irq(&mcp->lock); 163 if (mcp->use_count++ == 0) 164 mcp->ops->enable(mcp); 165 spin_unlock_irq(&mcp->lock); 166 } 167 EXPORT_SYMBOL(mcp_enable); 168 169 /** 170 * mcp_disable - disable the MCP interface 171 * @mcp: MCP interface to disable 172 * 173 * Disable the MCP interface. The MCP interface will only be 174 * disabled once the number of calls to mcp_enable matches the 175 * number of calls to mcp_disable. 176 */ 177 void mcp_disable(struct mcp *mcp) 178 { 179 unsigned long flags; 180 181 spin_lock_irqsave(&mcp->lock, flags); 182 if (--mcp->use_count == 0) 183 mcp->ops->disable(mcp); 184 spin_unlock_irqrestore(&mcp->lock, flags); 185 } 186 EXPORT_SYMBOL(mcp_disable); 187 188 static void mcp_release(struct device *dev) 189 { 190 struct mcp *mcp = container_of(dev, struct mcp, attached_device); 191 192 kfree(mcp); 193 } 194 195 struct mcp *mcp_host_alloc(struct device *parent, size_t size) 196 { 197 struct mcp *mcp; 198 199 mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL); 200 if (mcp) { 201 memset(mcp, 0, sizeof(struct mcp) + size); 202 spin_lock_init(&mcp->lock); 203 mcp->attached_device.parent = parent; 204 mcp->attached_device.bus = &mcp_bus_type; 205 mcp->attached_device.dma_mask = parent->dma_mask; 206 mcp->attached_device.release = mcp_release; 207 } 208 return mcp; 209 } 210 EXPORT_SYMBOL(mcp_host_alloc); 211 212 int mcp_host_register(struct mcp *mcp) 213 { 214 strcpy(mcp->attached_device.bus_id, "mcp0"); 215 return device_register(&mcp->attached_device); 216 } 217 EXPORT_SYMBOL(mcp_host_register); 218 219 void mcp_host_unregister(struct mcp *mcp) 220 { 221 device_unregister(&mcp->attached_device); 222 } 223 EXPORT_SYMBOL(mcp_host_unregister); 224 225 int mcp_driver_register(struct mcp_driver *mcpdrv) 226 { 227 mcpdrv->drv.bus = &mcp_bus_type; 228 mcpdrv->drv.probe = mcp_bus_probe; 229 mcpdrv->drv.remove = mcp_bus_remove; 230 return driver_register(&mcpdrv->drv); 231 } 232 EXPORT_SYMBOL(mcp_driver_register); 233 234 void mcp_driver_unregister(struct mcp_driver *mcpdrv) 235 { 236 driver_unregister(&mcpdrv->drv); 237 } 238 EXPORT_SYMBOL(mcp_driver_unregister); 239 240 static int __init mcp_init(void) 241 { 242 return bus_register(&mcp_bus_type); 243 } 244 245 static void __exit mcp_exit(void) 246 { 247 bus_unregister(&mcp_bus_type); 248 } 249 250 module_init(mcp_init); 251 module_exit(mcp_exit); 252 253 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); 254 MODULE_DESCRIPTION("Core multimedia communications port driver"); 255 MODULE_LICENSE("GPL"); 256