aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/can/mcp251x.c
diff options
context:
space:
mode:
authorAlexander Shiyan <shc_work@mail.ru>2013-12-21 00:01:41 -0500
committerMarc Kleine-Budde <mkl@pengutronix.de>2013-12-21 09:04:24 -0500
commit66606aafd8cd6cffbefa463b27e1f16e793e40a9 (patch)
treed4b9c8e4d0fdfe8fb99306a73747d287f0e34985 /drivers/net/can/mcp251x.c
parentc0ebbdd6b57949775d428f00b8696a4078f86ac4 (diff)
can: mcp251x: Add device tree support
This patch adds Device Tree support to the Microchip MCP251X driver. Signed-off-by: Alexander Shiyan <shc_work@mail.ru> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can/mcp251x.c')
-rw-r--r--drivers/net/can/mcp251x.c99
1 files changed, 74 insertions, 25 deletions
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 88d3877b6277..cdb9808d12db 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -58,6 +58,7 @@
58#include <linux/can/dev.h> 58#include <linux/can/dev.h>
59#include <linux/can/led.h> 59#include <linux/can/led.h>
60#include <linux/can/platform/mcp251x.h> 60#include <linux/can/platform/mcp251x.h>
61#include <linux/clk.h>
61#include <linux/completion.h> 62#include <linux/completion.h>
62#include <linux/delay.h> 63#include <linux/delay.h>
63#include <linux/device.h> 64#include <linux/device.h>
@@ -68,6 +69,8 @@
68#include <linux/kernel.h> 69#include <linux/kernel.h>
69#include <linux/module.h> 70#include <linux/module.h>
70#include <linux/netdevice.h> 71#include <linux/netdevice.h>
72#include <linux/of.h>
73#include <linux/of_device.h>
71#include <linux/platform_device.h> 74#include <linux/platform_device.h>
72#include <linux/slab.h> 75#include <linux/slab.h>
73#include <linux/spi/spi.h> 76#include <linux/spi/spi.h>
@@ -263,6 +266,7 @@ struct mcp251x_priv {
263 int restart_tx; 266 int restart_tx;
264 struct regulator *power; 267 struct regulator *power;
265 struct regulator *transceiver; 268 struct regulator *transceiver;
269 struct clk *clk;
266}; 270};
267 271
268#define MCP251X_IS(_model) \ 272#define MCP251X_IS(_model) \
@@ -994,22 +998,65 @@ static const struct net_device_ops mcp251x_netdev_ops = {
994 .ndo_start_xmit = mcp251x_hard_start_xmit, 998 .ndo_start_xmit = mcp251x_hard_start_xmit,
995}; 999};
996 1000
1001static const struct of_device_id mcp251x_of_match[] = {
1002 {
1003 .compatible = "microchip,mcp2510",
1004 .data = (void *)CAN_MCP251X_MCP2510,
1005 },
1006 {
1007 .compatible = "microchip,mcp2515",
1008 .data = (void *)CAN_MCP251X_MCP2515,
1009 },
1010 { }
1011};
1012MODULE_DEVICE_TABLE(of, mcp251x_of_match);
1013
1014static const struct spi_device_id mcp251x_id_table[] = {
1015 {
1016 .name = "mcp2510",
1017 .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2510,
1018 },
1019 {
1020 .name = "mcp2515",
1021 .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2515,
1022 },
1023 { }
1024};
1025MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
1026
997static int mcp251x_can_probe(struct spi_device *spi) 1027static int mcp251x_can_probe(struct spi_device *spi)
998{ 1028{
1029 const struct of_device_id *of_id = of_match_device(mcp251x_of_match,
1030 &spi->dev);
1031 struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
999 struct net_device *net; 1032 struct net_device *net;
1000 struct mcp251x_priv *priv; 1033 struct mcp251x_priv *priv;
1001 struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev); 1034 int freq, ret = -ENODEV;
1002 int ret = -ENODEV; 1035 struct clk *clk;
1036
1037 clk = devm_clk_get(&spi->dev, NULL);
1038 if (IS_ERR(clk)) {
1039 if (pdata)
1040 freq = pdata->oscillator_frequency;
1041 else
1042 return PTR_ERR(clk);
1043 } else {
1044 freq = clk_get_rate(clk);
1045 }
1003 1046
1004 if (!pdata) 1047 /* Sanity check */
1005 /* Platform data is required for osc freq */ 1048 if (freq < 1000000 || freq > 25000000)
1006 goto error_out; 1049 return -ERANGE;
1007 1050
1008 /* Allocate can/net device */ 1051 /* Allocate can/net device */
1009 net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX); 1052 net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
1010 if (!net) { 1053 if (!net)
1011 ret = -ENOMEM; 1054 return -ENOMEM;
1012 goto error_alloc; 1055
1056 if (!IS_ERR(clk)) {
1057 ret = clk_prepare_enable(clk);
1058 if (ret)
1059 goto out_free;
1013 } 1060 }
1014 1061
1015 net->netdev_ops = &mcp251x_netdev_ops; 1062 net->netdev_ops = &mcp251x_netdev_ops;
@@ -1018,23 +1065,27 @@ static int mcp251x_can_probe(struct spi_device *spi)
1018 priv = netdev_priv(net); 1065 priv = netdev_priv(net);
1019 priv->can.bittiming_const = &mcp251x_bittiming_const; 1066 priv->can.bittiming_const = &mcp251x_bittiming_const;
1020 priv->can.do_set_mode = mcp251x_do_set_mode; 1067 priv->can.do_set_mode = mcp251x_do_set_mode;
1021 priv->can.clock.freq = pdata->oscillator_frequency / 2; 1068 priv->can.clock.freq = freq / 2;
1022 priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | 1069 priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
1023 CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY; 1070 CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
1024 priv->model = spi_get_device_id(spi)->driver_data; 1071 if (of_id)
1072 priv->model = (enum mcp251x_model)of_id->data;
1073 else
1074 priv->model = spi_get_device_id(spi)->driver_data;
1025 priv->net = net; 1075 priv->net = net;
1076 priv->clk = clk;
1026 1077
1027 priv->power = devm_regulator_get(&spi->dev, "vdd"); 1078 priv->power = devm_regulator_get(&spi->dev, "vdd");
1028 priv->transceiver = devm_regulator_get(&spi->dev, "xceiver"); 1079 priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
1029 if ((PTR_ERR(priv->power) == -EPROBE_DEFER) || 1080 if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
1030 (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) { 1081 (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
1031 ret = -EPROBE_DEFER; 1082 ret = -EPROBE_DEFER;
1032 goto error_power; 1083 goto out_clk;
1033 } 1084 }
1034 1085
1035 ret = mcp251x_power_enable(priv->power, 1); 1086 ret = mcp251x_power_enable(priv->power, 1);
1036 if (ret) 1087 if (ret)
1037 goto error_power; 1088 goto out_clk;
1038 1089
1039 spi_set_drvdata(spi, priv); 1090 spi_set_drvdata(spi, priv);
1040 1091
@@ -1113,11 +1164,14 @@ error_probe:
1113 dma_free_coherent(&spi->dev, PAGE_SIZE, 1164 dma_free_coherent(&spi->dev, PAGE_SIZE,
1114 priv->spi_tx_buf, priv->spi_tx_dma); 1165 priv->spi_tx_buf, priv->spi_tx_dma);
1115 mcp251x_power_enable(priv->power, 0); 1166 mcp251x_power_enable(priv->power, 0);
1116error_power: 1167
1168out_clk:
1169 if (!IS_ERR(clk))
1170 clk_disable_unprepare(clk);
1171
1172out_free:
1117 free_candev(net); 1173 free_candev(net);
1118error_alloc: 1174
1119 dev_err(&spi->dev, "probe failed\n");
1120error_out:
1121 return ret; 1175 return ret;
1122} 1176}
1123 1177
@@ -1135,6 +1189,9 @@ static int mcp251x_can_remove(struct spi_device *spi)
1135 1189
1136 mcp251x_power_enable(priv->power, 0); 1190 mcp251x_power_enable(priv->power, 0);
1137 1191
1192 if (!IS_ERR(priv->clk))
1193 clk_disable_unprepare(priv->clk);
1194
1138 free_candev(net); 1195 free_candev(net);
1139 1196
1140 return 0; 1197 return 0;
@@ -1197,21 +1254,13 @@ static int mcp251x_can_resume(struct device *dev)
1197static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend, 1254static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
1198 mcp251x_can_resume); 1255 mcp251x_can_resume);
1199 1256
1200static const struct spi_device_id mcp251x_id_table[] = {
1201 { "mcp2510", CAN_MCP251X_MCP2510 },
1202 { "mcp2515", CAN_MCP251X_MCP2515 },
1203 { },
1204};
1205
1206MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
1207
1208static struct spi_driver mcp251x_can_driver = { 1257static struct spi_driver mcp251x_can_driver = {
1209 .driver = { 1258 .driver = {
1210 .name = DEVICE_NAME, 1259 .name = DEVICE_NAME,
1211 .owner = THIS_MODULE, 1260 .owner = THIS_MODULE,
1261 .of_match_table = mcp251x_of_match,
1212 .pm = &mcp251x_can_pm_ops, 1262 .pm = &mcp251x_can_pm_ops,
1213 }, 1263 },
1214
1215 .id_table = mcp251x_id_table, 1264 .id_table = mcp251x_id_table,
1216 .probe = mcp251x_can_probe, 1265 .probe = mcp251x_can_probe,
1217 .remove = mcp251x_can_remove, 1266 .remove = mcp251x_can_remove,