Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[MFD] Add multimedia communication port core support

Add support for the core of the multimedia communication port
framework. This is a port used to communicate with devices
with two DMA paths and a control path.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Russell King and committed by
Russell King
a4e137ab 099d44e8

+341 -1
+2
arch/arm/Kconfig
··· 752 752 753 753 source "drivers/misc/Kconfig" 754 754 755 + source "drivers/mfd/Kconfig" 756 + 755 757 source "drivers/media/Kconfig" 756 758 757 759 source "drivers/video/Kconfig"
+2
drivers/Kconfig
··· 48 48 49 49 source "drivers/misc/Kconfig" 50 50 51 + source "drivers/mfd/Kconfig" 52 + 51 53 source "drivers/media/Kconfig" 52 54 53 55 source "drivers/video/Kconfig"
+1 -1
drivers/Makefile
··· 26 26 obj-$(CONFIG_SERIO) += input/serio/ 27 27 obj-y += serial/ 28 28 obj-$(CONFIG_PARPORT) += parport/ 29 - obj-y += base/ block/ misc/ net/ media/ 29 + obj-y += base/ block/ misc/ mfd/ net/ media/ 30 30 obj-$(CONFIG_NUBUS) += nubus/ 31 31 obj-$(CONFIG_ATM) += atm/ 32 32 obj-$(CONFIG_PPC_PMAC) += macintosh/
+10
drivers/mfd/Kconfig
··· 1 + # 2 + # Multifunction miscellaneous devices 3 + # 4 + 5 + menu "Multimedia Capabilities Port drivers" 6 + 7 + config MCP 8 + tristate 9 + 10 + endmenu
+5
drivers/mfd/Makefile
··· 1 + # 2 + # Makefile for multifunction miscellaneous devices 3 + # 4 + 5 + obj-$(CONFIG_MCP) += mcp-core.o
+255
drivers/mfd/mcp-core.c
··· 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");
+66
drivers/mfd/mcp.h
··· 1 + /* 2 + * linux/drivers/mfd/mcp.h 3 + * 4 + * Copyright (C) 2001 Russell King, 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 as published by 8 + * the Free Software Foundation; either version 2 of the License. 9 + */ 10 + #ifndef MCP_H 11 + #define MCP_H 12 + 13 + struct mcp_ops; 14 + 15 + struct mcp { 16 + struct module *owner; 17 + struct mcp_ops *ops; 18 + spinlock_t lock; 19 + int use_count; 20 + unsigned int sclk_rate; 21 + unsigned int rw_timeout; 22 + dma_device_t dma_audio_rd; 23 + dma_device_t dma_audio_wr; 24 + dma_device_t dma_telco_rd; 25 + dma_device_t dma_telco_wr; 26 + struct device attached_device; 27 + }; 28 + 29 + struct mcp_ops { 30 + void (*set_telecom_divisor)(struct mcp *, unsigned int); 31 + void (*set_audio_divisor)(struct mcp *, unsigned int); 32 + void (*reg_write)(struct mcp *, unsigned int, unsigned int); 33 + unsigned int (*reg_read)(struct mcp *, unsigned int); 34 + void (*enable)(struct mcp *); 35 + void (*disable)(struct mcp *); 36 + }; 37 + 38 + void mcp_set_telecom_divisor(struct mcp *, unsigned int); 39 + void mcp_set_audio_divisor(struct mcp *, unsigned int); 40 + void mcp_reg_write(struct mcp *, unsigned int, unsigned int); 41 + unsigned int mcp_reg_read(struct mcp *, unsigned int); 42 + void mcp_enable(struct mcp *); 43 + void mcp_disable(struct mcp *); 44 + #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) 45 + 46 + struct mcp *mcp_host_alloc(struct device *, size_t); 47 + int mcp_host_register(struct mcp *); 48 + void mcp_host_unregister(struct mcp *); 49 + 50 + struct mcp_driver { 51 + struct device_driver drv; 52 + int (*probe)(struct mcp *); 53 + void (*remove)(struct mcp *); 54 + int (*suspend)(struct mcp *, pm_message_t); 55 + int (*resume)(struct mcp *); 56 + }; 57 + 58 + int mcp_driver_register(struct mcp_driver *); 59 + void mcp_driver_unregister(struct mcp_driver *); 60 + 61 + #define mcp_get_drvdata(mcp) dev_get_drvdata(&(mcp)->attached_device) 62 + #define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d) 63 + 64 + #define mcp_priv(mcp) ((void *)((mcp)+1)) 65 + 66 + #endif