On 07/11/2014 03:59 PM, Dong Aisheng wrote: (...)
+/* m_can private data structure */ +struct m_can_priv { + struct can_priv can; /* must be the first member */ + struct napi_struct napi; + struct net_device *dev; + struct device *device; + struct clk *hclk; + struct clk *cclk; + void __iomem *base; + u32 irqstatus; + + /* message ram configuration */ + void __iomem *mram_base; + struct mram_cfg mcfg[MRAM_CFG_NUM]; +}; +
It will be good if we write the comments for the driver private structure
+static inline u32 m_can_read(const struct m_can_priv *priv, enum m_can_reg reg) +{ + return readl(priv->base + reg); +} +
(...)
+static void free_m_can_dev(struct net_device *dev) +{ + free_candev(dev); +} +
Why do we need a separate function which calls a single function... :-)
+static struct net_device *alloc_m_can_dev(void) +{ + struct net_device *dev; + struct m_can_priv *priv; + + dev = alloc_candev(sizeof(struct m_can_priv), 1);
sizeof(*priv)...?
+ if (!dev) + return NULL;
Return value -ENOMEM ?
+ + priv = netdev_priv(dev); + netif_napi_add(dev, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT); + + priv->dev = dev; + priv->can.bittiming_const = &m_can_bittiming_const; + priv->can.do_set_mode = m_can_set_mode; + priv->can.do_get_berr_counter = m_can_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_BERR_REPORTING; + + return dev; +} + +static int m_can_open(struct net_device *dev) +{ + struct m_can_priv *priv = netdev_priv(dev); + int err; + + err = clk_prepare_enable(priv->hclk); + if (err) + return err; + + err = clk_prepare_enable(priv->cclk); + if (err) + goto exit_disable_hclk; + + /* open the can device */ + err = open_candev(dev); + if (err) { + netdev_err(dev, "failed to open can device\n"); + goto exit_disable_cclk; + } + + /* register interrupt handler */ + err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name, + dev);
why don't we use devm_request_irq()...? If you use this no need to worry about freeing the irq
+ if (err < 0) { + netdev_err(dev, "failed to request interrupt\n"); + goto exit_irq_fail; + } + + /* start the m_can controller */ + m_can_start(dev); + + can_led_event(dev, CAN_LED_EVENT_OPEN); + napi_enable(&priv->napi); + netif_start_queue(dev); + + return 0; + +exit_irq_fail: + close_candev(dev); +exit_disable_cclk: + clk_disable_unprepare(priv->cclk); +exit_disable_hclk: + clk_disable_unprepare(priv->hclk); + return err; +} + +static void m_can_stop(struct net_device *dev) +{ + struct m_can_priv *priv = netdev_priv(dev); + + /* disable all interrupts */ + m_can_disable_all_interrupts(priv); + + clk_disable_unprepare(priv->hclk); + clk_disable_unprepare(priv->cclk); + + /* set the state as STOPPED */ + priv->can.state = CAN_STATE_STOPPED; +} + +static int m_can_close(struct net_device *dev) +{ + struct m_can_priv *priv = netdev_priv(dev); + + netif_stop_queue(dev); + napi_disable(&priv->napi); + m_can_stop(dev); + free_irq(dev->irq, dev);
not required when you use devm_request_irq()
+ close_candev(dev); + can_led_event(dev, CAN_LED_EVENT_STOP); + + return 0; +} +
(...)
+ +static const struct of_device_id m_can_of_table[] = { + { .compatible = "bosch,m_can", .data = NULL },
we can simply give '0' . No need of .data = NULL. Things should be simple right.... :-)
+ { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, m_can_of_table); + +static int m_can_of_parse_mram(struct platform_device *pdev, + struct m_can_priv *priv) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + void __iomem *addr; + u32 out_val[MRAM_CFG_LEN]; + int ret; + + /* message ram could be shared */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram"); + if (!res) + return -ENODEV; + + addr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!addr) + return -ENODEV;
Is this err return is appropriate ... ?
+ + /* get message ram configuration */ + ret = of_property_read_u32_array(np, "mram-cfg", + out_val, sizeof(out_val) / 4); + if (ret) { + dev_err(&pdev->dev, "can not get message ram configuration\n"); + return -ENODEV; + } +
Is this err return is appropriate ... ?
+ priv->mram_base = addr; + priv->mcfg[MRAM_SIDF].off = out_val[0]; + priv->mcfg[MRAM_SIDF].num = out_val[1]; + priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off + + priv->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE; + priv->mcfg[MRAM_XIDF].num = out_val[2]; + priv->mcfg[MRAM_RXF0].off = priv->mcfg[MRAM_XIDF].off + + priv->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE; + priv->mcfg[MRAM_RXF0].num = out_val[3] & RXFC_FS_MASK; + priv->mcfg[MRAM_RXF1].off = priv->mcfg[MRAM_RXF0].off + + priv->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE; + priv->mcfg[MRAM_RXF1].num = out_val[4] & RXFC_FS_MASK; + priv->mcfg[MRAM_RXB].off = priv->mcfg[MRAM_RXF1].off + + priv->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE; + priv->mcfg[MRAM_RXB].num = out_val[5]; + priv->mcfg[MRAM_TXE].off = priv->mcfg[MRAM_RXB].off + + priv->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE; + priv->mcfg[MRAM_TXE].num = out_val[6]; + priv->mcfg[MRAM_TXB].off = priv->mcfg[MRAM_TXE].off + + priv->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE; + priv->mcfg[MRAM_TXB].num = out_val[7] & TXBC_NDTB_MASK; + + dev_dbg(&pdev->dev, "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n", + priv->mram_base, + priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num, + priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num, + priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num, + priv->mcfg[MRAM_RXF1].off, priv->mcfg[MRAM_RXF1].num, + priv->mcfg[MRAM_RXB].off, priv->mcfg[MRAM_RXB].num, + priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num, + priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num); +
dev_dbg() will insert the new lines in b/w. It wont print the values as you expected. Check this by enabling debug ...
+ return 0; +} +
(...)
+ +static void unregister_m_can_dev(struct net_device *dev) +{ + unregister_candev(dev); +} +
again a function which calls a single func.
+static int m_can_plat_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + unregister_m_can_dev(dev); + platform_set_drvdata(pdev, NULL); + + free_m_can_dev(dev); + + return 0; +} + +static const struct dev_pm_ops m_can_pmops = { + SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume) +}; + +static struct platform_driver m_can_plat_driver = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE,
No need to update .owner. module_platform_driver() will do for you. see:http://lxr.free-electrons.com/source/include/linux/platform_device.h#L190
+ .of_match_table = of_match_ptr(m_can_of_table), + .pm = &m_can_pmops, + }, + .probe = m_can_plat_probe, + .remove = m_can_plat_remove, +}; + +module_platform_driver(m_can_plat_driver); + +MODULE_AUTHOR("Dong Aisheng <b29396@xxxxxxxxxxxxx>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
-- Regards, Varka Bhadram. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html