Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dabf54dd authored by Yegor Yefremov's avatar Yegor Yefremov Committed by Marc Kleine-Budde
Browse files

can: ti_hecc: Convert TI HECC driver to DT only driver



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: default avatarAnton Glukhov <anton.a.glukhov@gmail.com>
Signed-off-by: default avatarYegor Yefremov <yegorslists@googlemail.com>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 869a78a2
Loading
Loading
Loading
Loading
+88 −82
Original line number Diff line number Diff line
@@ -17,25 +17,6 @@
 *
 */

/*
 * 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>
@@ -46,11 +27,13 @@
#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,
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 @@ static int ti_hecc_probe(struct platform_device *pdev)
	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,
+0 −44
Original line number Diff line number Diff line
#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 */