Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  linux/drivers/mfd/mcp-core.c
0004  *
0005  *  Copyright (C) 2001 Russell King
0006  *
0007  *  Generic MCP (Multimedia Communications Port) layer.  All MCP locking
0008  *  is solely held within this file.
0009  */
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/errno.h>
0013 #include <linux/smp.h>
0014 #include <linux/device.h>
0015 #include <linux/slab.h>
0016 #include <linux/string.h>
0017 #include <linux/mfd/mcp.h>
0018 
0019 
0020 #define to_mcp(d)       container_of(d, struct mcp, attached_device)
0021 #define to_mcp_driver(d)    container_of(d, struct mcp_driver, drv)
0022 
0023 static int mcp_bus_match(struct device *dev, struct device_driver *drv)
0024 {
0025     return 1;
0026 }
0027 
0028 static int mcp_bus_probe(struct device *dev)
0029 {
0030     struct mcp *mcp = to_mcp(dev);
0031     struct mcp_driver *drv = to_mcp_driver(dev->driver);
0032 
0033     return drv->probe(mcp);
0034 }
0035 
0036 static void mcp_bus_remove(struct device *dev)
0037 {
0038     struct mcp *mcp = to_mcp(dev);
0039     struct mcp_driver *drv = to_mcp_driver(dev->driver);
0040 
0041     drv->remove(mcp);
0042 }
0043 
0044 static struct bus_type mcp_bus_type = {
0045     .name       = "mcp",
0046     .match      = mcp_bus_match,
0047     .probe      = mcp_bus_probe,
0048     .remove     = mcp_bus_remove,
0049 };
0050 
0051 /**
0052  *  mcp_set_telecom_divisor - set the telecom divisor
0053  *  @mcp: MCP interface structure
0054  *  @div: SIB clock divisor
0055  *
0056  *  Set the telecom divisor on the MCP interface.  The resulting
0057  *  sample rate is SIBCLOCK/div.
0058  */
0059 void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
0060 {
0061     unsigned long flags;
0062 
0063     spin_lock_irqsave(&mcp->lock, flags);
0064     mcp->ops->set_telecom_divisor(mcp, div);
0065     spin_unlock_irqrestore(&mcp->lock, flags);
0066 }
0067 EXPORT_SYMBOL(mcp_set_telecom_divisor);
0068 
0069 /**
0070  *  mcp_set_audio_divisor - set the audio divisor
0071  *  @mcp: MCP interface structure
0072  *  @div: SIB clock divisor
0073  *
0074  *  Set the audio divisor on the MCP interface.
0075  */
0076 void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
0077 {
0078     unsigned long flags;
0079 
0080     spin_lock_irqsave(&mcp->lock, flags);
0081     mcp->ops->set_audio_divisor(mcp, div);
0082     spin_unlock_irqrestore(&mcp->lock, flags);
0083 }
0084 EXPORT_SYMBOL(mcp_set_audio_divisor);
0085 
0086 /**
0087  *  mcp_reg_write - write a device register
0088  *  @mcp: MCP interface structure
0089  *  @reg: 4-bit register index
0090  *  @val: 16-bit data value
0091  *
0092  *  Write a device register.  The MCP interface must be enabled
0093  *  to prevent this function hanging.
0094  */
0095 void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
0096 {
0097     unsigned long flags;
0098 
0099     spin_lock_irqsave(&mcp->lock, flags);
0100     mcp->ops->reg_write(mcp, reg, val);
0101     spin_unlock_irqrestore(&mcp->lock, flags);
0102 }
0103 EXPORT_SYMBOL(mcp_reg_write);
0104 
0105 /**
0106  *  mcp_reg_read - read a device register
0107  *  @mcp: MCP interface structure
0108  *  @reg: 4-bit register index
0109  *
0110  *  Read a device register and return its value.  The MCP interface
0111  *  must be enabled to prevent this function hanging.
0112  */
0113 unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
0114 {
0115     unsigned long flags;
0116     unsigned int val;
0117 
0118     spin_lock_irqsave(&mcp->lock, flags);
0119     val = mcp->ops->reg_read(mcp, reg);
0120     spin_unlock_irqrestore(&mcp->lock, flags);
0121 
0122     return val;
0123 }
0124 EXPORT_SYMBOL(mcp_reg_read);
0125 
0126 /**
0127  *  mcp_enable - enable the MCP interface
0128  *  @mcp: MCP interface to enable
0129  *
0130  *  Enable the MCP interface.  Each call to mcp_enable will need
0131  *  a corresponding call to mcp_disable to disable the interface.
0132  */
0133 void mcp_enable(struct mcp *mcp)
0134 {
0135     unsigned long flags;
0136 
0137     spin_lock_irqsave(&mcp->lock, flags);
0138     if (mcp->use_count++ == 0)
0139         mcp->ops->enable(mcp);
0140     spin_unlock_irqrestore(&mcp->lock, flags);
0141 }
0142 EXPORT_SYMBOL(mcp_enable);
0143 
0144 /**
0145  *  mcp_disable - disable the MCP interface
0146  *  @mcp: MCP interface to disable
0147  *
0148  *  Disable the MCP interface.  The MCP interface will only be
0149  *  disabled once the number of calls to mcp_enable matches the
0150  *  number of calls to mcp_disable.
0151  */
0152 void mcp_disable(struct mcp *mcp)
0153 {
0154     unsigned long flags;
0155 
0156     spin_lock_irqsave(&mcp->lock, flags);
0157     if (--mcp->use_count == 0)
0158         mcp->ops->disable(mcp);
0159     spin_unlock_irqrestore(&mcp->lock, flags);
0160 }
0161 EXPORT_SYMBOL(mcp_disable);
0162 
0163 static void mcp_release(struct device *dev)
0164 {
0165     struct mcp *mcp = container_of(dev, struct mcp, attached_device);
0166 
0167     kfree(mcp);
0168 }
0169 
0170 struct mcp *mcp_host_alloc(struct device *parent, size_t size)
0171 {
0172     struct mcp *mcp;
0173 
0174     mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
0175     if (mcp) {
0176         spin_lock_init(&mcp->lock);
0177         device_initialize(&mcp->attached_device);
0178         mcp->attached_device.parent = parent;
0179         mcp->attached_device.bus = &mcp_bus_type;
0180         mcp->attached_device.dma_mask = parent->dma_mask;
0181         mcp->attached_device.release = mcp_release;
0182     }
0183     return mcp;
0184 }
0185 EXPORT_SYMBOL(mcp_host_alloc);
0186 
0187 int mcp_host_add(struct mcp *mcp, void *pdata)
0188 {
0189     mcp->attached_device.platform_data = pdata;
0190     dev_set_name(&mcp->attached_device, "mcp0");
0191     return device_add(&mcp->attached_device);
0192 }
0193 EXPORT_SYMBOL(mcp_host_add);
0194 
0195 void mcp_host_del(struct mcp *mcp)
0196 {
0197     device_del(&mcp->attached_device);
0198 }
0199 EXPORT_SYMBOL(mcp_host_del);
0200 
0201 void mcp_host_free(struct mcp *mcp)
0202 {
0203     put_device(&mcp->attached_device);
0204 }
0205 EXPORT_SYMBOL(mcp_host_free);
0206 
0207 int mcp_driver_register(struct mcp_driver *mcpdrv)
0208 {
0209     mcpdrv->drv.bus = &mcp_bus_type;
0210     return driver_register(&mcpdrv->drv);
0211 }
0212 EXPORT_SYMBOL(mcp_driver_register);
0213 
0214 void mcp_driver_unregister(struct mcp_driver *mcpdrv)
0215 {
0216     driver_unregister(&mcpdrv->drv);
0217 }
0218 EXPORT_SYMBOL(mcp_driver_unregister);
0219 
0220 static int __init mcp_init(void)
0221 {
0222     return bus_register(&mcp_bus_type);
0223 }
0224 
0225 static void __exit mcp_exit(void)
0226 {
0227     bus_unregister(&mcp_bus_type);
0228 }
0229 
0230 module_init(mcp_init);
0231 module_exit(mcp_exit);
0232 
0233 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
0234 MODULE_DESCRIPTION("Core multimedia communications port driver");
0235 MODULE_LICENSE("GPL");