| /* |
| * Copyright (C) 2009-2011, 2014 Freescale Semiconductor, Inc. All Rights Reserved. |
| */ |
| |
| /* |
| * The code contained herein is licensed under the GNU General Public |
| * License. You may obtain a copy of the GNU General Public License |
| * Version 2 or later at the following locations: |
| * |
| * http://www.opensource.org/licenses/gpl-license.html |
| * http://www.gnu.org/copyleft/gpl.html |
| */ |
| |
| #include <linux/fs.h> |
| #include <linux/init.h> |
| #include <linux/platform_device.h> |
| #include <linux/err.h> |
| #include <linux/mm.h> |
| #include <linux/miscdevice.h> |
| #include <linux/module.h> |
| #include <linux/of.h> |
| |
| static unsigned long iim_reg_base0, iim_reg_end0, iim_reg_size0; |
| static unsigned long iim_reg_base1, iim_reg_end1, iim_reg_size1; |
| static struct device *iim_dev; |
| |
| /*! |
| * MXS Virtual IIM interface - memory map function |
| * This function maps one page size VIIM registers from VIIM base address0 |
| * if the size of the required virtual memory space is less than or equal to |
| * one page size, otherwise this function will also map one page size VIIM |
| * registers from VIIM base address1. |
| * |
| * @param file struct file * |
| * @param vma structure vm_area_struct * |
| * |
| * @return Return 0 on success or negative error code on error |
| */ |
| static int mxs_viim_mmap(struct file *file, struct vm_area_struct *vma) |
| { |
| size_t size = vma->vm_end - vma->vm_start; |
| |
| vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
| |
| /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ |
| if (remap_pfn_range(vma, |
| vma->vm_start, |
| iim_reg_base0 >> PAGE_SHIFT, |
| iim_reg_size0, |
| vma->vm_page_prot)) |
| return -EAGAIN; |
| |
| if (size > iim_reg_size0) { |
| if (remap_pfn_range(vma, |
| vma->vm_start + iim_reg_size0, |
| iim_reg_base1 >> PAGE_SHIFT, |
| iim_reg_size1, |
| vma->vm_page_prot)) |
| return -EAGAIN; |
| } |
| |
| return 0; |
| } |
| |
| /*! |
| * MXS Virtual IIM interface - open function |
| * |
| * @param inode struct inode * |
| * @param filp struct file * |
| * |
| * @return Return 0 on success or negative error code on error |
| */ |
| static int mxs_viim_open(struct inode *inode, struct file *filp) |
| { |
| return 0; |
| } |
| |
| /*! |
| * MXS Virtual IIM interface - release function |
| * |
| * @param inode struct inode * |
| * @param filp struct file * |
| * |
| * @return Return 0 on success or negative error code on error |
| */ |
| static int mxs_viim_release(struct inode *inode, struct file *filp) |
| { |
| return 0; |
| } |
| |
| static const struct file_operations mxs_viim_fops = { |
| .mmap = mxs_viim_mmap, |
| .open = mxs_viim_open, |
| .release = mxs_viim_release, |
| }; |
| |
| static struct miscdevice mxs_viim_miscdev = { |
| .minor = MISC_DYNAMIC_MINOR, |
| .name = "mxs_viim", |
| .fops = &mxs_viim_fops, |
| }; |
| |
| /*! |
| * This function is called by the driver framework to get virtual iim base/end |
| * address and register iim misc device. |
| * |
| * @param dev The device structure for Virtual IIM passed in by the |
| * driver framework. |
| * |
| * @return Returns 0 on success or negative error code on error |
| */ |
| static int mxs_viim_probe(struct platform_device *pdev) |
| { |
| struct resource *res; |
| int ret; |
| |
| iim_dev = &pdev->dev; |
| |
| res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| if (IS_ERR(res)) { |
| dev_err(iim_dev, "Unable to get Virtual IIM resource 0\n"); |
| return -ENODEV; |
| } |
| |
| iim_reg_base0 = res->start; |
| iim_reg_end0 = res->end; |
| iim_reg_size0 = iim_reg_end0 - iim_reg_base0 + 1; |
| |
| res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| if (IS_ERR(res)) { |
| dev_err(iim_dev, "Unable to get Virtual IIM resource 1\n"); |
| return -ENODEV; |
| } |
| |
| iim_reg_base1 = res->start; |
| iim_reg_end1 = res->end; |
| iim_reg_size1 = iim_reg_end1 - iim_reg_base1 + 1; |
| |
| ret = misc_register(&mxs_viim_miscdev); |
| if (ret) |
| return ret; |
| |
| return 0; |
| } |
| |
| static int mxs_viim_remove(struct platform_device *pdev) |
| { |
| misc_deregister(&mxs_viim_miscdev); |
| return 0; |
| } |
| |
| static const struct of_device_id mxs_viim_dt_ids[] = { |
| { .compatible = "fsl,mxs_viim", }, |
| { /* sentinel */ } |
| }; |
| MODULE_DEVICE_TABLE(of, mxs_viim_dt_ids); |
| |
| static struct platform_driver mxs_viim_driver = { |
| .driver = { |
| .owner = THIS_MODULE, |
| .name = "mxs_viim", |
| .of_match_table = mxs_viim_dt_ids, |
| }, |
| .probe = mxs_viim_probe, |
| .remove = mxs_viim_remove, |
| }; |
| module_platform_driver(mxs_viim_driver); |
| |
| MODULE_AUTHOR("Freescale Semiconductor, Inc."); |
| MODULE_DESCRIPTION("IMX Virtual IIM driver"); |
| MODULE_LICENSE("GPL"); |
| MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR); |