diff options
author | Damien Riegel <damien.riegel@savoirfairelinux.com> | 2016-01-12 17:31:18 -0500 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2016-02-20 08:56:00 -0500 |
commit | f49cbe6b7988b51aa2b72c45d4332fabea62fba6 (patch) | |
tree | a1cfd97d66ceff39821f8f686f4f3609d3a55252 /drivers/net/can | |
parent | 80c804bfc487c6df783c258b9034b9d81c34f7a0 (diff) |
can: sja1000: of: add per-compatible init hook
This commit adds the capability to allocate and init private data
embedded in the sja1000_priv structure on a per-compatible basis. The
device node is passed as a parameter of the init callback to allow
parsing of custom device tree properties.
Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r-- | drivers/net/can/sja1000/sja1000_platform.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 0552ed46a206..777d312f1779 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/can/platform/sja1000.h> | 27 | #include <linux/can/platform/sja1000.h> |
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/of.h> | 29 | #include <linux/of.h> |
30 | #include <linux/of_device.h> | ||
30 | #include <linux/of_irq.h> | 31 | #include <linux/of_irq.h> |
31 | 32 | ||
32 | #include "sja1000.h" | 33 | #include "sja1000.h" |
@@ -40,6 +41,11 @@ MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); | |||
40 | MODULE_ALIAS("platform:" DRV_NAME); | 41 | MODULE_ALIAS("platform:" DRV_NAME); |
41 | MODULE_LICENSE("GPL v2"); | 42 | MODULE_LICENSE("GPL v2"); |
42 | 43 | ||
44 | struct sja1000_of_data { | ||
45 | size_t priv_sz; | ||
46 | int (*init)(struct sja1000_priv *priv, struct device_node *of); | ||
47 | }; | ||
48 | |||
43 | static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) | 49 | static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) |
44 | { | 50 | { |
45 | return ioread8(priv->reg_base + reg); | 51 | return ioread8(priv->reg_base + reg); |
@@ -154,6 +160,12 @@ static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of) | |||
154 | priv->cdr |= CDR_CBP; /* default */ | 160 | priv->cdr |= CDR_CBP; /* default */ |
155 | } | 161 | } |
156 | 162 | ||
163 | static const struct of_device_id sp_of_table[] = { | ||
164 | { .compatible = "nxp,sja1000", .data = NULL, }, | ||
165 | { /* sentinel */ }, | ||
166 | }; | ||
167 | MODULE_DEVICE_TABLE(of, sp_of_table); | ||
168 | |||
157 | static int sp_probe(struct platform_device *pdev) | 169 | static int sp_probe(struct platform_device *pdev) |
158 | { | 170 | { |
159 | int err, irq = 0; | 171 | int err, irq = 0; |
@@ -163,6 +175,9 @@ static int sp_probe(struct platform_device *pdev) | |||
163 | struct resource *res_mem, *res_irq = NULL; | 175 | struct resource *res_mem, *res_irq = NULL; |
164 | struct sja1000_platform_data *pdata; | 176 | struct sja1000_platform_data *pdata; |
165 | struct device_node *of = pdev->dev.of_node; | 177 | struct device_node *of = pdev->dev.of_node; |
178 | const struct of_device_id *of_id; | ||
179 | const struct sja1000_of_data *of_data = NULL; | ||
180 | size_t priv_sz = 0; | ||
166 | 181 | ||
167 | pdata = dev_get_platdata(&pdev->dev); | 182 | pdata = dev_get_platdata(&pdev->dev); |
168 | if (!pdata && !of) { | 183 | if (!pdata && !of) { |
@@ -191,7 +206,13 @@ static int sp_probe(struct platform_device *pdev) | |||
191 | if (!irq && !res_irq) | 206 | if (!irq && !res_irq) |
192 | return -ENODEV; | 207 | return -ENODEV; |
193 | 208 | ||
194 | dev = alloc_sja1000dev(0); | 209 | of_id = of_match_device(sp_of_table, &pdev->dev); |
210 | if (of_id && of_id->data) { | ||
211 | of_data = of_id->data; | ||
212 | priv_sz = of_data->priv_sz; | ||
213 | } | ||
214 | |||
215 | dev = alloc_sja1000dev(priv_sz); | ||
195 | if (!dev) | 216 | if (!dev) |
196 | return -ENOMEM; | 217 | return -ENOMEM; |
197 | priv = netdev_priv(dev); | 218 | priv = netdev_priv(dev); |
@@ -208,10 +229,17 @@ static int sp_probe(struct platform_device *pdev) | |||
208 | dev->irq = irq; | 229 | dev->irq = irq; |
209 | priv->reg_base = addr; | 230 | priv->reg_base = addr; |
210 | 231 | ||
211 | if (of) | 232 | if (of) { |
212 | sp_populate_of(priv, of); | 233 | sp_populate_of(priv, of); |
213 | else | 234 | |
235 | if (of_data && of_data->init) { | ||
236 | err = of_data->init(priv, of); | ||
237 | if (err) | ||
238 | goto exit_free; | ||
239 | } | ||
240 | } else { | ||
214 | sp_populate(priv, pdata, res_mem->flags); | 241 | sp_populate(priv, pdata, res_mem->flags); |
242 | } | ||
215 | 243 | ||
216 | platform_set_drvdata(pdev, dev); | 244 | platform_set_drvdata(pdev, dev); |
217 | SET_NETDEV_DEV(dev, &pdev->dev); | 245 | SET_NETDEV_DEV(dev, &pdev->dev); |
@@ -242,12 +270,6 @@ static int sp_remove(struct platform_device *pdev) | |||
242 | return 0; | 270 | return 0; |
243 | } | 271 | } |
244 | 272 | ||
245 | static const struct of_device_id sp_of_table[] = { | ||
246 | {.compatible = "nxp,sja1000"}, | ||
247 | {}, | ||
248 | }; | ||
249 | MODULE_DEVICE_TABLE(of, sp_of_table); | ||
250 | |||
251 | static struct platform_driver sp_driver = { | 273 | static struct platform_driver sp_driver = { |
252 | .probe = sp_probe, | 274 | .probe = sp_probe, |
253 | .remove = sp_remove, | 275 | .remove = sp_remove, |