118 lines
2.9 KiB
C
118 lines
2.9 KiB
C
|
/*
|
||
|
* drivers/stm/miphy_pcie_mp.c
|
||
|
*
|
||
|
* Copyright (c) 2010 STMicroelectronics Limited
|
||
|
* Author: Srinivas.Kandagatla <srinivas.kandagatla@st.com>
|
||
|
*
|
||
|
* May be copied or modified under the terms of the GNU General Public
|
||
|
* License Version 2.0 only. See linux/COPYING for more information.
|
||
|
*
|
||
|
*
|
||
|
* Support for the UPort interface to MiPhy.
|
||
|
*/
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/err.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/io.h>
|
||
|
#include <linux/stm/pio.h>
|
||
|
#include <linux/stm/platform.h>
|
||
|
#include <linux/stm/miphy.h>
|
||
|
#include "miphy.h"
|
||
|
|
||
|
#define NAME "pcie-mp"
|
||
|
|
||
|
struct pcie_mp_device{
|
||
|
struct stm_miphy_device miphy_dev;
|
||
|
void __iomem *mp_base;
|
||
|
void (*mp_select)(int port);
|
||
|
struct miphy_if_ops *ops;
|
||
|
};
|
||
|
static struct pcie_mp_device *mp_dev;
|
||
|
|
||
|
static void stm_pcie_mp_register_write(int miphyselect, u8 address, u8 data)
|
||
|
{
|
||
|
BUG_ON(!mp_dev || !mp_dev->mp_select);
|
||
|
mp_dev->mp_select(miphyselect);
|
||
|
iowrite8(data, mp_dev->mp_base + address);
|
||
|
}
|
||
|
|
||
|
static u8 stm_pcie_mp_register_read(int miphyselect, u8 address)
|
||
|
{
|
||
|
u8 data;
|
||
|
BUG_ON(!mp_dev || !mp_dev->mp_select);
|
||
|
mp_dev->mp_select(miphyselect);
|
||
|
data = ioread8(mp_dev->mp_base + address);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
static const struct miphy_if_ops stm_miphy_mp_ops = {
|
||
|
.reg_write = stm_pcie_mp_register_write,
|
||
|
.reg_read = stm_pcie_mp_register_read,
|
||
|
};
|
||
|
|
||
|
static int __init pcie_mp_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
struct resource *res;
|
||
|
struct stm_plat_pcie_mp_data *data =
|
||
|
(struct stm_plat_pcie_mp_data *)pdev->dev.platform_data;
|
||
|
int result;
|
||
|
|
||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||
|
|
||
|
mp_dev = kzalloc(sizeof(struct pcie_mp_device), GFP_KERNEL);
|
||
|
if (!mp_dev)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||
|
res->end - res->start, "pcie-mp")) {
|
||
|
printk(KERN_ERR NAME " Request mem 0x%x region failed\n",
|
||
|
res->start);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
mp_dev->mp_base = devm_ioremap_nocache(&pdev->dev,
|
||
|
res->start, resource_size(res));
|
||
|
mp_dev->mp_select = data->mp_select;
|
||
|
|
||
|
if (!mp_dev->mp_base)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
result = miphy_if_register(&mp_dev->miphy_dev, UPORT_IF,
|
||
|
data->miphy_first, data->miphy_count, data->miphy_modes,
|
||
|
&pdev->dev, &stm_miphy_mp_ops);
|
||
|
|
||
|
if (result) {
|
||
|
printk(KERN_ERR "Unable to Register uPort MiPHY device\n");
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
static int pcie_mp_remove(struct platform_device *pdev)
|
||
|
{
|
||
|
miphy_if_unregister(&mp_dev->miphy_dev);
|
||
|
kfree(mp_dev->ops);
|
||
|
kfree(mp_dev);
|
||
|
mp_dev = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct platform_driver pcie_mp_driver = {
|
||
|
.driver.name = NAME,
|
||
|
.driver.owner = THIS_MODULE,
|
||
|
.probe = pcie_mp_probe,
|
||
|
.remove = pcie_mp_remove,
|
||
|
};
|
||
|
|
||
|
static int __init pcie_mp_init(void)
|
||
|
{
|
||
|
return platform_driver_register(&pcie_mp_driver);
|
||
|
}
|
||
|
|
||
|
postcore_initcall(pcie_mp_init);
|
||
|
|
||
|
MODULE_AUTHOR("Srinivas.Kandagatla <srinivas.kandagatla@st.com>");
|
||
|
MODULE_DESCRIPTION("STM PCIE-UPort driver");
|
||
|
MODULE_LICENSE("GPL");
|