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