cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/can/cc770/cc770_platform.c

/*
 * Driver for CC770 and AN82527 CAN controllers on the platform bus
 *
 * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the version 2 of the GNU General Public License
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

/*
 * If platform data are used you should have similar definitions
 * in your board-specific code:
 *
 *   static struct cc770_platform_data myboard_cc770_pdata = {
 *           .osc_freq = 16000000,
 *           .cir = 0x41,
 *           .cor = 0x20,
 *           .bcr = 0x40,
 *   };
 *
 * Please see include/linux/can/platform/cc770.h for description of
 * above fields.
 *
 * If the device tree is used, you need a CAN node definition in your
 * DTS file similar to:
 *
 *   can@3,100 {
 *           compatible = "bosch,cc770";
 *           reg = <3 0x100 0x80>;
 *           interrupts = <2 0>;
 *           interrupt-parent = <&mpic>;
 *           bosch,external-clock-frequency = <16000000>;
 *   };
 *
 * See "Documentation/devicetree/bindings/net/can/cc770.txt" for further
 * information.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/platform/cc770.h>

#include "cc770.h"


#define DRV_NAME "cc770_platform"

MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the platform bus");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);


#define CC770_PLATFORM_CAN_CLOCK  16000000


static u8 cc770_platform_read_reg(const struct cc770_priv *priv, int reg) { return ioread8(priv->reg_base + reg); }

Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger25100.00%1100.00%
Total25100.00%1100.00%


static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg, u8 val) { iowrite8(val, priv->reg_base + reg); }

Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger29100.00%1100.00%
Total29100.00%1100.00%


static int cc770_get_of_node_data(struct platform_device *pdev, struct cc770_priv *priv) { struct device_node *np = pdev->dev.of_node; const u32 *prop; int prop_size; u32 clkext; prop = of_get_property(np, "bosch,external-clock-frequency", &prop_size); if (prop && (prop_size == sizeof(u32))) clkext = *prop; else clkext = CC770_PLATFORM_CAN_CLOCK; /* default */ priv->can.clock.freq = clkext; /* The system clock may not exceed 10 MHz */ if (priv->can.clock.freq > 10000000) { priv->cpu_interface |= CPUIF_DSC; priv->can.clock.freq /= 2; } /* The memory clock may not exceed 8 MHz */ if (priv->can.clock.freq > 8000000) priv->cpu_interface |= CPUIF_DMC; if (of_get_property(np, "bosch,divide-memory-clock", NULL)) priv->cpu_interface |= CPUIF_DMC; if (of_get_property(np, "bosch,iso-low-speed-mux", NULL)) priv->cpu_interface |= CPUIF_MUX; if (!of_get_property(np, "bosch,no-comperator-bypass", NULL)) priv->bus_config |= BUSCFG_CBY; if (of_get_property(np, "bosch,disconnect-rx0-input", NULL)) priv->bus_config |= BUSCFG_DR0; if (of_get_property(np, "bosch,disconnect-rx1-input", NULL)) priv->bus_config |= BUSCFG_DR1; if (of_get_property(np, "bosch,disconnect-tx1-output", NULL)) priv->bus_config |= BUSCFG_DT1; if (of_get_property(np, "bosch,polarity-dominant", NULL)) priv->bus_config |= BUSCFG_POL; prop = of_get_property(np, "bosch,clock-out-frequency", &prop_size); if (prop && (prop_size == sizeof(u32)) && *prop > 0) { u32 cdv = clkext / *prop; int slew; if (cdv > 0 && cdv < 16) { priv->cpu_interface |= CPUIF_CEN; priv->clkout |= (cdv - 1) & CLKOUT_CD_MASK; prop = of_get_property(np, "bosch,slew-rate", &prop_size); if (prop && (prop_size == sizeof(u32))) { slew = *prop; } else { /* Determine default slew rate */ slew = (CLKOUT_SL_MASK >> CLKOUT_SL_SHIFT) - ((cdv * clkext - 1) / 8000000); if (slew < 0) slew = 0; } priv->clkout |= (slew << CLKOUT_SL_SHIFT) & CLKOUT_SL_MASK; } else { dev_dbg(&pdev->dev, "invalid clock-out-frequency\n"); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger421100.00%1100.00%
Total421100.00%1100.00%


static int cc770_get_platform_data(struct platform_device *pdev, struct cc770_priv *priv) { struct cc770_platform_data *pdata = dev_get_platdata(&pdev->dev); priv->can.clock.freq = pdata->osc_freq; if (priv->cpu_interface & CPUIF_DSC) priv->can.clock.freq /= 2; priv->clkout = pdata->cor; priv->bus_config = pdata->bcr; priv->cpu_interface = pdata->cir; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger8194.19%133.33%
Jingoo Han44.65%133.33%
Joe Perches11.16%133.33%
Total86100.00%3100.00%


static int cc770_platform_probe(struct platform_device *pdev) { struct net_device *dev; struct cc770_priv *priv; struct resource *mem; resource_size_t mem_size; void __iomem *base; int err, irq; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!mem || irq <= 0) return -ENODEV; mem_size = resource_size(mem); if (!request_mem_region(mem->start, mem_size, pdev->name)) return -EBUSY; base = ioremap(mem->start, mem_size); if (!base) { err = -ENOMEM; goto exit_release_mem; } dev = alloc_cc770dev(0); if (!dev) { err = -ENOMEM; goto exit_unmap_mem; } dev->irq = irq; priv = netdev_priv(dev); priv->read_reg = cc770_platform_read_reg; priv->write_reg = cc770_platform_write_reg; priv->irq_flags = IRQF_SHARED; priv->reg_base = base; if (pdev->dev.of_node) err = cc770_get_of_node_data(pdev, priv); else if (dev_get_platdata(&pdev->dev)) err = cc770_get_platform_data(pdev, priv); else err = -ENODEV; if (err) goto exit_free_cc770; dev_dbg(&pdev->dev, "reg_base=0x%p irq=%d clock=%d cpu_interface=0x%02x " "bus_config=0x%02x clkout=0x%02x\n", priv->reg_base, dev->irq, priv->can.clock.freq, priv->cpu_interface, priv->bus_config, priv->clkout); platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_cc770dev(dev); if (err) { dev_err(&pdev->dev, "couldn't register CC700 device (err=%d)\n", err); goto exit_free_cc770; } return 0; exit_free_cc770: free_cc770dev(dev); exit_unmap_mem: iounmap(base); exit_release_mem: release_mem_region(mem->start, mem_size); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger34498.57%133.33%
Jingoo Han51.43%266.67%
Total349100.00%3100.00%


static int cc770_platform_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct cc770_priv *priv = netdev_priv(dev); struct resource *mem; unregister_cc770dev(dev); iounmap(priv->reg_base); free_cc770dev(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger7898.73%150.00%
Jingoo Han11.27%150.00%
Total79100.00%2100.00%

static const struct of_device_id cc770_platform_table[] = { {.compatible = "bosch,cc770"}, /* CC770 from Bosch */ {.compatible = "intc,82527"}, /* AN82527 from Intel CP */ {}, }; MODULE_DEVICE_TABLE(of, cc770_platform_table); static struct platform_driver cc770_platform_driver = { .driver = { .name = DRV_NAME, .of_match_table = cc770_platform_table, }, .probe = cc770_platform_probe, .remove = cc770_platform_remove, }; module_platform_driver(cc770_platform_driver);

Overall Contributors

PersonTokensPropCommitsCommitProp
Wolfgang Grandegger109997.78%116.67%
Marc Kleine-Budde131.16%116.67%
Jingoo Han100.89%233.33%
Fabian Frederick10.09%116.67%
Joe Perches10.09%116.67%
Total1124100.00%6100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.