can: ti_hecc: Convert TI HECC driver to DT only driver
authorYegor Yefremov <yegorslists@googlemail.com>
Fri, 17 Feb 2017 15:52:33 +0000 (16:52 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 4 Apr 2017 14:55:26 +0000 (16:55 +0200)
This patch converts TI HECC driver to DT only driver. This results in
removing ti_hecc.h containing now obsolete platform data.

Former transceiver_switch callback function will be now modelled via
regulator API.

Signed-off-by: Anton Glukhov <anton.a.glukhov@gmail.com>
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/ti_hecc.c
include/linux/can/platform/ti_hecc.h [deleted file]

index 6749b18..b8aac53 100644 (file)
  *
  */
 
-/*
- * Your platform definitions should specify module ram offsets and interrupt
- * number to use as follows:
- *
- * static struct ti_hecc_platform_data am3517_evm_hecc_pdata = {
- *         .scc_hecc_offset        = 0,
- *         .scc_ram_offset         = 0x3000,
- *         .hecc_ram_offset        = 0x3000,
- *         .mbx_offset             = 0x2000,
- *         .int_line               = 0,
- *         .revision               = 1,
- *         .transceiver_switch     = hecc_phy_control,
- * };
- *
- * Please see include/linux/can/platform/ti_hecc.h for description of
- * above fields.
- *
- */
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 #include <linux/can/led.h>
-#include <linux/can/platform/ti_hecc.h>
 
 #define DRV_NAME "ti_hecc"
 #define HECC_MODULE_VERSION     "0.7"
@@ -214,15 +197,14 @@ struct ti_hecc_priv {
        struct net_device *ndev;
        struct clk *clk;
        void __iomem *base;
-       u32 scc_ram_offset;
-       u32 hecc_ram_offset;
-       u32 mbx_offset;
-       u32 int_line;
+       void __iomem *hecc_ram;
+       void __iomem *mbx;
+       bool use_hecc1int;
        spinlock_t mbx_lock; /* CANME register needs protection */
        u32 tx_head;
        u32 tx_tail;
        u32 rx_next;
-       void (*transceiver_switch)(int);
+       struct regulator *reg_xceiver;
 };
 
 static inline int get_tx_head_mb(struct ti_hecc_priv *priv)
@@ -242,20 +224,18 @@ static inline int get_tx_head_prio(struct ti_hecc_priv *priv)
 
 static inline void hecc_write_lam(struct ti_hecc_priv *priv, u32 mbxno, u32 val)
 {
-       __raw_writel(val, priv->base + priv->hecc_ram_offset + mbxno * 4);
+       __raw_writel(val, priv->hecc_ram + mbxno * 4);
 }
 
 static inline void hecc_write_mbx(struct ti_hecc_priv *priv, u32 mbxno,
        u32 reg, u32 val)
 {
-       __raw_writel(val, priv->base + priv->mbx_offset + mbxno * 0x10 +
-                       reg);
+       __raw_writel(val, priv->mbx + mbxno * 0x10 + reg);
 }
 
 static inline u32 hecc_read_mbx(struct ti_hecc_priv *priv, u32 mbxno, u32 reg)
 {
-       return __raw_readl(priv->base + priv->mbx_offset + mbxno * 0x10 +
-                       reg);
+       return __raw_readl(priv->mbx + mbxno * 0x10 + reg);
 }
 
 static inline void hecc_write(struct ti_hecc_priv *priv, u32 reg, u32 val)
@@ -311,11 +291,16 @@ static int ti_hecc_set_btc(struct ti_hecc_priv *priv)
        return 0;
 }
 
-static void ti_hecc_transceiver_switch(const struct ti_hecc_priv *priv,
-                                       int on)
+static int ti_hecc_transceiver_switch(const struct ti_hecc_priv *priv,
+                                     int on)
 {
-       if (priv->transceiver_switch)
-               priv->transceiver_switch(on);
+       if (!priv->reg_xceiver)
+               return 0;
+
+       if (on)
+               return regulator_enable(priv->reg_xceiver);
+       else
+               return regulator_disable(priv->reg_xceiver);
 }
 
 static void ti_hecc_reset(struct net_device *ndev)
@@ -409,7 +394,7 @@ static void ti_hecc_start(struct net_device *ndev)
 
        /* Prevent message over-write & Enable interrupts */
        hecc_write(priv, HECC_CANOPC, HECC_SET_REG);
-       if (priv->int_line) {
+       if (priv->use_hecc1int) {
                hecc_write(priv, HECC_CANMIL, HECC_SET_REG);
                hecc_write(priv, HECC_CANGIM, HECC_CANGIM_DEF_MASK |
                        HECC_CANGIM_I1EN | HECC_CANGIM_SIL);
@@ -760,7 +745,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
        unsigned long ack, flags;
 
        int_status = hecc_read(priv,
-               (priv->int_line) ? HECC_CANGIF1 : HECC_CANGIF0);
+               (priv->use_hecc1int) ? HECC_CANGIF1 : HECC_CANGIF0);
 
        if (!int_status)
                return IRQ_NONE;
@@ -806,7 +791,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
        }
 
        /* clear all interrupt conditions - read back to avoid spurious ints */
-       if (priv->int_line) {
+       if (priv->use_hecc1int) {
                hecc_write(priv, HECC_CANGIF1, HECC_SET_REG);
                int_status = hecc_read(priv, HECC_CANGIF1);
        } else {
@@ -872,58 +857,87 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
        .ndo_change_mtu         = can_change_mtu,
 };
 
+static const struct of_device_id ti_hecc_dt_ids[] = {
+       {
+               .compatible = "ti,am3517-hecc",
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ti_hecc_dt_ids);
+
 static int ti_hecc_probe(struct platform_device *pdev)
 {
        struct net_device *ndev = (struct net_device *)0;
        struct ti_hecc_priv *priv;
-       struct ti_hecc_platform_data *pdata;
-       struct resource *mem, *irq;
-       void __iomem *addr;
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res, *irq;
+       struct regulator *reg_xceiver;
        int err = -ENODEV;
 
-       pdata = dev_get_platdata(&pdev->dev);
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platform data\n");
-               goto probe_exit;
+       if (!IS_ENABLED(CONFIG_OF) || !np)
+               return -EINVAL;
+
+       reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+       if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       else if (IS_ERR(reg_xceiver))
+               reg_xceiver = NULL;
+
+       ndev = alloc_candev(sizeof(struct ti_hecc_priv), HECC_MAX_TX_MBOX);
+       if (!ndev) {
+               dev_err(&pdev->dev, "alloc_candev failed\n");
+               return -ENOMEM;
        }
+       priv = netdev_priv(ndev);
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "No mem resources\n");
-               goto probe_exit;
+       /* handle hecc memory */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hecc");
+       if (!res) {
+               dev_err(&pdev->dev, "can't get IORESOURCE_MEM hecc\n");
+               return -EINVAL;
        }
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "No irq resource\n");
-               goto probe_exit;
+
+       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       if (!priv->base) {
+               dev_err(&pdev->dev, "hecc ioremap failed\n");
+               return -ENOMEM;
        }
-       if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
-               dev_err(&pdev->dev, "HECC region already claimed\n");
-               err = -EBUSY;
-               goto probe_exit;
+
+       /* handle hecc-ram memory */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hecc-ram");
+       if (!res) {
+               dev_err(&pdev->dev, "can't get IORESOURCE_MEM hecc-ram\n");
+               return -EINVAL;
        }
-       addr = ioremap(mem->start, resource_size(mem));
-       if (!addr) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               err = -ENOMEM;
-               goto probe_exit_free_region;
+
+       priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res);
+       if (!priv->hecc_ram) {
+               dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
+               return -ENOMEM;
        }
 
-       ndev = alloc_candev(sizeof(struct ti_hecc_priv), HECC_MAX_TX_MBOX);
-       if (!ndev) {
-               dev_err(&pdev->dev, "alloc_candev failed\n");
-               err = -ENOMEM;
-               goto probe_exit_iounmap;
+       /* handle mbx memory */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mbx");
+       if (!res) {
+               dev_err(&pdev->dev, "can't get IORESOURCE_MEM mbx\n");
+               return -EINVAL;
+       }
+
+       priv->mbx = devm_ioremap_resource(&pdev->dev, res);
+       if (!priv->mbx) {
+               dev_err(&pdev->dev, "mbx ioremap failed\n");
+               return -ENOMEM;
+       }
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "No irq resource\n");
+               goto probe_exit;
        }
 
-       priv = netdev_priv(ndev);
        priv->ndev = ndev;
-       priv->base = addr;
-       priv->scc_ram_offset = pdata->scc_ram_offset;
-       priv->hecc_ram_offset = pdata->hecc_ram_offset;
-       priv->mbx_offset = pdata->mbx_offset;
-       priv->int_line = pdata->int_line;
-       priv->transceiver_switch = pdata->transceiver_switch;
+       priv->reg_xceiver = reg_xceiver;
+       priv->use_hecc1int = of_property_read_bool(np, "ti,use-hecc1int");
 
        priv->can.bittiming_const = &ti_hecc_bittiming_const;
        priv->can.do_set_mode = ti_hecc_do_set_mode;
@@ -971,32 +985,23 @@ probe_exit_clk:
        clk_put(priv->clk);
 probe_exit_candev:
        free_candev(ndev);
-probe_exit_iounmap:
-       iounmap(addr);
-probe_exit_free_region:
-       release_mem_region(mem->start, resource_size(mem));
 probe_exit:
        return err;
 }
 
 static int ti_hecc_remove(struct platform_device *pdev)
 {
-       struct resource *res;
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct ti_hecc_priv *priv = netdev_priv(ndev);
 
        unregister_candev(ndev);
        clk_disable_unprepare(priv->clk);
        clk_put(priv->clk);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       iounmap(priv->base);
-       release_mem_region(res->start, resource_size(res));
        free_candev(ndev);
 
        return 0;
 }
 
-
 #ifdef CONFIG_PM
 static int ti_hecc_suspend(struct platform_device *pdev, pm_message_t state)
 {
@@ -1045,6 +1050,7 @@ static int ti_hecc_resume(struct platform_device *pdev)
 static struct platform_driver ti_hecc_driver = {
        .driver = {
                .name    = DRV_NAME,
+               .of_match_table = ti_hecc_dt_ids,
        },
        .probe = ti_hecc_probe,
        .remove = ti_hecc_remove,
diff --git a/include/linux/can/platform/ti_hecc.h b/include/linux/can/platform/ti_hecc.h
deleted file mode 100644 (file)
index a52f47c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _CAN_PLATFORM_TI_HECC_H
-#define _CAN_PLATFORM_TI_HECC_H
-
-/*
- * TI HECC (High End CAN Controller) driver platform header
- *
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed as is WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-/**
- * struct hecc_platform_data - HECC Platform Data
- *
- * @scc_hecc_offset:   mostly 0 - should really never change
- * @scc_ram_offset:    SCC RAM offset
- * @hecc_ram_offset:   HECC RAM offset
- * @mbx_offset:                Mailbox RAM offset
- * @int_line:          Interrupt line to use - 0 or 1
- * @version:           version for future use
- * @transceiver_switch:        platform specific callback fn for transceiver control
- *
- * Platform data structure to get all platform specific settings.
- * this structure also accounts the fact that the IP may have different
- * RAM and mailbox offsets for different SOC's
- */
-struct ti_hecc_platform_data {
-       u32 scc_hecc_offset;
-       u32 scc_ram_offset;
-       u32 hecc_ram_offset;
-       u32 mbx_offset;
-       u32 int_line;
-       u32 version;
-       void (*transceiver_switch) (int);
-};
-#endif /* !_CAN_PLATFORM_TI_HECC_H */