linux/drivers/mfd/mcp-core.c
<<
>>
Prefs
   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 <mach/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
  29static int mcp_bus_match(struct device *dev, struct device_driver *drv)
  30{
  31        return 1;
  32}
  33
  34static 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
  42static 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
  51static 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
  64static 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
  77static 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 */
  94void 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}
 100EXPORT_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 */
 109void 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}
 115EXPORT_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 */
 126void 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}
 134EXPORT_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 */
 144unsigned 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}
 155EXPORT_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 */
 164void 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}
 171EXPORT_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 */
 181void 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}
 190EXPORT_SYMBOL(mcp_disable);
 191
 192static void mcp_release(struct device *dev)
 193{
 194        struct mcp *mcp = container_of(dev, struct mcp, attached_device);
 195
 196        kfree(mcp);
 197}
 198
 199struct 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}
 213EXPORT_SYMBOL(mcp_host_alloc);
 214
 215int mcp_host_register(struct mcp *mcp)
 216{
 217        dev_set_name(&mcp->attached_device, "mcp0");
 218        return device_register(&mcp->attached_device);
 219}
 220EXPORT_SYMBOL(mcp_host_register);
 221
 222void mcp_host_unregister(struct mcp *mcp)
 223{
 224        device_unregister(&mcp->attached_device);
 225}
 226EXPORT_SYMBOL(mcp_host_unregister);
 227
 228int mcp_driver_register(struct mcp_driver *mcpdrv)
 229{
 230        mcpdrv->drv.bus = &mcp_bus_type;
 231        return driver_register(&mcpdrv->drv);
 232}
 233EXPORT_SYMBOL(mcp_driver_register);
 234
 235void mcp_driver_unregister(struct mcp_driver *mcpdrv)
 236{
 237        driver_unregister(&mcpdrv->drv);
 238}
 239EXPORT_SYMBOL(mcp_driver_unregister);
 240
 241static int __init mcp_init(void)
 242{
 243        return bus_register(&mcp_bus_type);
 244}
 245
 246static void __exit mcp_exit(void)
 247{
 248        bus_unregister(&mcp_bus_type);
 249}
 250
 251module_init(mcp_init);
 252module_exit(mcp_exit);
 253
 254MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 255MODULE_DESCRIPTION("Core multimedia communications port driver");
 256MODULE_LICENSE("GPL");
 257