0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/platform_device.h>
0009 #include <linux/phy/phy.h>
0010
0011 #include "m_can.h"
0012
0013 struct m_can_plat_priv {
0014 struct m_can_classdev cdev;
0015
0016 void __iomem *base;
0017 void __iomem *mram_base;
0018 };
0019
0020 static inline struct m_can_plat_priv *cdev_to_priv(struct m_can_classdev *cdev)
0021 {
0022 return container_of(cdev, struct m_can_plat_priv, cdev);
0023 }
0024
0025 static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
0026 {
0027 struct m_can_plat_priv *priv = cdev_to_priv(cdev);
0028
0029 return readl(priv->base + reg);
0030 }
0031
0032 static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
0033 {
0034 struct m_can_plat_priv *priv = cdev_to_priv(cdev);
0035 void __iomem *src = priv->mram_base + offset;
0036
0037 while (val_count--) {
0038 *(unsigned int *)val = ioread32(src);
0039 val += 4;
0040 src += 4;
0041 }
0042
0043 return 0;
0044 }
0045
0046 static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
0047 {
0048 struct m_can_plat_priv *priv = cdev_to_priv(cdev);
0049
0050 writel(val, priv->base + reg);
0051
0052 return 0;
0053 }
0054
0055 static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
0056 const void *val, size_t val_count)
0057 {
0058 struct m_can_plat_priv *priv = cdev_to_priv(cdev);
0059 void __iomem *dst = priv->mram_base + offset;
0060
0061 while (val_count--) {
0062 iowrite32(*(unsigned int *)val, dst);
0063 val += 4;
0064 dst += 4;
0065 }
0066
0067 return 0;
0068 }
0069
0070 static struct m_can_ops m_can_plat_ops = {
0071 .read_reg = iomap_read_reg,
0072 .write_reg = iomap_write_reg,
0073 .write_fifo = iomap_write_fifo,
0074 .read_fifo = iomap_read_fifo,
0075 };
0076
0077 static int m_can_plat_probe(struct platform_device *pdev)
0078 {
0079 struct m_can_classdev *mcan_class;
0080 struct m_can_plat_priv *priv;
0081 struct resource *res;
0082 void __iomem *addr;
0083 void __iomem *mram_addr;
0084 struct phy *transceiver;
0085 int irq, ret = 0;
0086
0087 mcan_class = m_can_class_allocate_dev(&pdev->dev,
0088 sizeof(struct m_can_plat_priv));
0089 if (!mcan_class)
0090 return -ENOMEM;
0091
0092 priv = cdev_to_priv(mcan_class);
0093
0094 ret = m_can_class_get_clocks(mcan_class);
0095 if (ret)
0096 goto probe_fail;
0097
0098 addr = devm_platform_ioremap_resource_byname(pdev, "m_can");
0099 irq = platform_get_irq_byname(pdev, "int0");
0100 if (IS_ERR(addr) || irq < 0) {
0101 ret = -EINVAL;
0102 goto probe_fail;
0103 }
0104
0105
0106 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
0107 if (!res) {
0108 ret = -ENODEV;
0109 goto probe_fail;
0110 }
0111
0112 mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
0113 if (!mram_addr) {
0114 ret = -ENOMEM;
0115 goto probe_fail;
0116 }
0117
0118 transceiver = devm_phy_optional_get(&pdev->dev, NULL);
0119 if (IS_ERR(transceiver)) {
0120 ret = PTR_ERR(transceiver);
0121 dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
0122 goto probe_fail;
0123 }
0124
0125 if (transceiver)
0126 mcan_class->can.bitrate_max = transceiver->attrs.max_link_rate;
0127
0128 priv->base = addr;
0129 priv->mram_base = mram_addr;
0130
0131 mcan_class->net->irq = irq;
0132 mcan_class->pm_clock_support = 1;
0133 mcan_class->can.clock.freq = clk_get_rate(mcan_class->cclk);
0134 mcan_class->dev = &pdev->dev;
0135 mcan_class->transceiver = transceiver;
0136
0137 mcan_class->ops = &m_can_plat_ops;
0138
0139 mcan_class->is_peripheral = false;
0140
0141 platform_set_drvdata(pdev, mcan_class);
0142
0143 ret = m_can_init_ram(mcan_class);
0144 if (ret)
0145 goto probe_fail;
0146
0147 pm_runtime_enable(mcan_class->dev);
0148 ret = m_can_class_register(mcan_class);
0149 if (ret)
0150 goto out_runtime_disable;
0151
0152 return ret;
0153
0154 out_runtime_disable:
0155 pm_runtime_disable(mcan_class->dev);
0156 probe_fail:
0157 m_can_class_free_dev(mcan_class->net);
0158 return ret;
0159 }
0160
0161 static __maybe_unused int m_can_suspend(struct device *dev)
0162 {
0163 return m_can_class_suspend(dev);
0164 }
0165
0166 static __maybe_unused int m_can_resume(struct device *dev)
0167 {
0168 return m_can_class_resume(dev);
0169 }
0170
0171 static int m_can_plat_remove(struct platform_device *pdev)
0172 {
0173 struct m_can_plat_priv *priv = platform_get_drvdata(pdev);
0174 struct m_can_classdev *mcan_class = &priv->cdev;
0175
0176 m_can_class_unregister(mcan_class);
0177
0178 m_can_class_free_dev(mcan_class->net);
0179
0180 return 0;
0181 }
0182
0183 static int __maybe_unused m_can_runtime_suspend(struct device *dev)
0184 {
0185 struct m_can_plat_priv *priv = dev_get_drvdata(dev);
0186 struct m_can_classdev *mcan_class = &priv->cdev;
0187
0188 clk_disable_unprepare(mcan_class->cclk);
0189 clk_disable_unprepare(mcan_class->hclk);
0190
0191 return 0;
0192 }
0193
0194 static int __maybe_unused m_can_runtime_resume(struct device *dev)
0195 {
0196 struct m_can_plat_priv *priv = dev_get_drvdata(dev);
0197 struct m_can_classdev *mcan_class = &priv->cdev;
0198 int err;
0199
0200 err = clk_prepare_enable(mcan_class->hclk);
0201 if (err)
0202 return err;
0203
0204 err = clk_prepare_enable(mcan_class->cclk);
0205 if (err)
0206 clk_disable_unprepare(mcan_class->hclk);
0207
0208 return err;
0209 }
0210
0211 static const struct dev_pm_ops m_can_pmops = {
0212 SET_RUNTIME_PM_OPS(m_can_runtime_suspend,
0213 m_can_runtime_resume, NULL)
0214 SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
0215 };
0216
0217 static const struct of_device_id m_can_of_table[] = {
0218 { .compatible = "bosch,m_can", .data = NULL },
0219 { },
0220 };
0221 MODULE_DEVICE_TABLE(of, m_can_of_table);
0222
0223 static struct platform_driver m_can_plat_driver = {
0224 .driver = {
0225 .name = KBUILD_MODNAME,
0226 .of_match_table = m_can_of_table,
0227 .pm = &m_can_pmops,
0228 },
0229 .probe = m_can_plat_probe,
0230 .remove = m_can_plat_remove,
0231 };
0232
0233 module_platform_driver(m_can_plat_driver);
0234
0235 MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
0236 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
0237 MODULE_LICENSE("GPL v2");
0238 MODULE_DESCRIPTION("M_CAN driver for IO Mapped Bosch controllers");