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