linux/drivers/bus/imx-weim.c
<<
>>
Prefs
   1/*
   2 * EIM driver for Freescale's i.MX chips
   3 *
   4 * Copyright (C) 2013 Freescale Semiconductor, Inc.
   5 *
   6 * This file is licensed under the terms of the GNU General Public
   7 * License version 2. This program is licensed "as is" without any
   8 * warranty of any kind, whether express or implied.
   9 */
  10#include <linux/module.h>
  11#include <linux/clk.h>
  12#include <linux/io.h>
  13#include <linux/of_device.h>
  14
  15struct imx_weim {
  16        void __iomem *base;
  17        struct clk *clk;
  18};
  19
  20static const struct of_device_id weim_id_table[] = {
  21        { .compatible = "fsl,imx6q-weim", },
  22        {}
  23};
  24MODULE_DEVICE_TABLE(of, weim_id_table);
  25
  26#define CS_TIMING_LEN 6
  27#define CS_REG_RANGE  0x18
  28
  29/* Parse and set the timing for this device. */
  30static int
  31weim_timing_setup(struct platform_device *pdev, struct device_node *np)
  32{
  33        struct imx_weim *weim = platform_get_drvdata(pdev);
  34        u32 value[CS_TIMING_LEN];
  35        u32 cs_idx;
  36        int ret;
  37        int i;
  38
  39        /* get the CS index from this child node's "reg" property. */
  40        ret = of_property_read_u32(np, "reg", &cs_idx);
  41        if (ret)
  42                return ret;
  43
  44        /* The weim has four chip selects. */
  45        if (cs_idx > 3)
  46                return -EINVAL;
  47
  48        ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
  49                                        value, CS_TIMING_LEN);
  50        if (ret)
  51                return ret;
  52
  53        /* set the timing for WEIM */
  54        for (i = 0; i < CS_TIMING_LEN; i++)
  55                writel(value[i], weim->base + cs_idx * CS_REG_RANGE + i * 4);
  56        return 0;
  57}
  58
  59static int weim_parse_dt(struct platform_device *pdev)
  60{
  61        struct device_node *child;
  62        int ret;
  63
  64        for_each_child_of_node(pdev->dev.of_node, child) {
  65                if (!child->name)
  66                        continue;
  67
  68                ret = weim_timing_setup(pdev, child);
  69                if (ret) {
  70                        dev_err(&pdev->dev, "%s set timing failed.\n",
  71                                child->full_name);
  72                        return ret;
  73                }
  74        }
  75
  76        ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
  77        if (ret)
  78                dev_err(&pdev->dev, "%s fail to create devices.\n",
  79                        pdev->dev.of_node->full_name);
  80        return ret;
  81}
  82
  83static int weim_probe(struct platform_device *pdev)
  84{
  85        struct imx_weim *weim;
  86        struct resource *res;
  87        int ret = -EINVAL;
  88
  89        weim = devm_kzalloc(&pdev->dev, sizeof(*weim), GFP_KERNEL);
  90        if (!weim) {
  91                ret = -ENOMEM;
  92                goto weim_err;
  93        }
  94        platform_set_drvdata(pdev, weim);
  95
  96        /* get the resource */
  97        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  98        weim->base = devm_ioremap_resource(&pdev->dev, res);
  99        if (IS_ERR(weim->base)) {
 100                ret = PTR_ERR(weim->base);
 101                goto weim_err;
 102        }
 103
 104        /* get the clock */
 105        weim->clk = devm_clk_get(&pdev->dev, NULL);
 106        if (IS_ERR(weim->clk))
 107                goto weim_err;
 108
 109        ret = clk_prepare_enable(weim->clk);
 110        if (ret)
 111                goto weim_err;
 112
 113        /* parse the device node */
 114        ret = weim_parse_dt(pdev);
 115        if (ret) {
 116                clk_disable_unprepare(weim->clk);
 117                goto weim_err;
 118        }
 119
 120        dev_info(&pdev->dev, "WEIM driver registered.\n");
 121        return 0;
 122
 123weim_err:
 124        return ret;
 125}
 126
 127static struct platform_driver weim_driver = {
 128        .driver = {
 129                .name = "imx-weim",
 130                .of_match_table = weim_id_table,
 131        },
 132        .probe   = weim_probe,
 133};
 134
 135module_platform_driver(weim_driver);
 136MODULE_AUTHOR("Freescale Semiconductor Inc.");
 137MODULE_DESCRIPTION("i.MX EIM Controller Driver");
 138MODULE_LICENSE("GPL");
 139
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.