Skip to content

Commit

Permalink
can: ti_hecc: Convert TI HECC driver to DT only driver
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Yegor Yefremov <[email protected]>
Signed-off-by: Marc Kleine-Budde <[email protected]>
  • Loading branch information
yegorich authored and marckleinebudde committed Apr 4, 2017
1 parent 869a78a commit dabf54d
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 126 deletions.
170 changes: 88 additions & 82 deletions drivers/net/can/ti_hecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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"
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down
44 changes: 0 additions & 44 deletions include/linux/can/platform/ti_hecc.h

This file was deleted.

0 comments on commit dabf54d

Please sign in to comment.