Commit 50c01fc355c6a97c511d58411f9bc0e4b8fc4659
Committed by
Grant Likely
1 parent
76d9cc454a
Exists in
master
and in
7 other branches
spi/dw_spi: don't treat NULL clk as an error
clk_get() returns a struct clk cookie to the driver and some platforms may return NULL if they only support a single clock. clk_get() has only failed if it returns a ERR_PTR() encoded pointer. Signed-off-by: Jamie Iles <jamie@jamieiles.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Showing 1 changed file with 3 additions and 2 deletions Inline Diff
drivers/spi/dw_spi_mmio.c
1 | /* | 1 | /* |
2 | * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core | 2 | * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core |
3 | * | 3 | * |
4 | * Copyright (c) 2010, Octasic semiconductor. | 4 | * Copyright (c) 2010, Octasic semiconductor. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
8 | * version 2, as published by the Free Software Foundation. | 8 | * version 2, as published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
12 | #include <linux/err.h> | ||
12 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
13 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
15 | #include <linux/spi/dw_spi.h> | 16 | #include <linux/spi/dw_spi.h> |
16 | #include <linux/spi/spi.h> | 17 | #include <linux/spi/spi.h> |
17 | 18 | ||
18 | #define DRIVER_NAME "dw_spi_mmio" | 19 | #define DRIVER_NAME "dw_spi_mmio" |
19 | 20 | ||
20 | struct dw_spi_mmio { | 21 | struct dw_spi_mmio { |
21 | struct dw_spi dws; | 22 | struct dw_spi dws; |
22 | struct clk *clk; | 23 | struct clk *clk; |
23 | }; | 24 | }; |
24 | 25 | ||
25 | static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) | 26 | static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) |
26 | { | 27 | { |
27 | struct dw_spi_mmio *dwsmmio; | 28 | struct dw_spi_mmio *dwsmmio; |
28 | struct dw_spi *dws; | 29 | struct dw_spi *dws; |
29 | struct resource *mem, *ioarea; | 30 | struct resource *mem, *ioarea; |
30 | int ret; | 31 | int ret; |
31 | 32 | ||
32 | dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL); | 33 | dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL); |
33 | if (!dwsmmio) { | 34 | if (!dwsmmio) { |
34 | ret = -ENOMEM; | 35 | ret = -ENOMEM; |
35 | goto err_end; | 36 | goto err_end; |
36 | } | 37 | } |
37 | 38 | ||
38 | dws = &dwsmmio->dws; | 39 | dws = &dwsmmio->dws; |
39 | 40 | ||
40 | /* Get basic io resource and map it */ | 41 | /* Get basic io resource and map it */ |
41 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 42 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
42 | if (!mem) { | 43 | if (!mem) { |
43 | dev_err(&pdev->dev, "no mem resource?\n"); | 44 | dev_err(&pdev->dev, "no mem resource?\n"); |
44 | ret = -EINVAL; | 45 | ret = -EINVAL; |
45 | goto err_kfree; | 46 | goto err_kfree; |
46 | } | 47 | } |
47 | 48 | ||
48 | ioarea = request_mem_region(mem->start, resource_size(mem), | 49 | ioarea = request_mem_region(mem->start, resource_size(mem), |
49 | pdev->name); | 50 | pdev->name); |
50 | if (!ioarea) { | 51 | if (!ioarea) { |
51 | dev_err(&pdev->dev, "SPI region already claimed\n"); | 52 | dev_err(&pdev->dev, "SPI region already claimed\n"); |
52 | ret = -EBUSY; | 53 | ret = -EBUSY; |
53 | goto err_kfree; | 54 | goto err_kfree; |
54 | } | 55 | } |
55 | 56 | ||
56 | dws->regs = ioremap_nocache(mem->start, resource_size(mem)); | 57 | dws->regs = ioremap_nocache(mem->start, resource_size(mem)); |
57 | if (!dws->regs) { | 58 | if (!dws->regs) { |
58 | dev_err(&pdev->dev, "SPI region already mapped\n"); | 59 | dev_err(&pdev->dev, "SPI region already mapped\n"); |
59 | ret = -ENOMEM; | 60 | ret = -ENOMEM; |
60 | goto err_release_reg; | 61 | goto err_release_reg; |
61 | } | 62 | } |
62 | 63 | ||
63 | dws->irq = platform_get_irq(pdev, 0); | 64 | dws->irq = platform_get_irq(pdev, 0); |
64 | if (dws->irq < 0) { | 65 | if (dws->irq < 0) { |
65 | dev_err(&pdev->dev, "no irq resource?\n"); | 66 | dev_err(&pdev->dev, "no irq resource?\n"); |
66 | ret = dws->irq; /* -ENXIO */ | 67 | ret = dws->irq; /* -ENXIO */ |
67 | goto err_unmap; | 68 | goto err_unmap; |
68 | } | 69 | } |
69 | 70 | ||
70 | dwsmmio->clk = clk_get(&pdev->dev, NULL); | 71 | dwsmmio->clk = clk_get(&pdev->dev, NULL); |
71 | if (!dwsmmio->clk) { | 72 | if (IS_ERR(dwsmmio->clk)) { |
72 | ret = -ENODEV; | 73 | ret = PTR_ERR(dwsmmio->clk); |
73 | goto err_irq; | 74 | goto err_irq; |
74 | } | 75 | } |
75 | clk_enable(dwsmmio->clk); | 76 | clk_enable(dwsmmio->clk); |
76 | 77 | ||
77 | dws->parent_dev = &pdev->dev; | 78 | dws->parent_dev = &pdev->dev; |
78 | dws->bus_num = 0; | 79 | dws->bus_num = 0; |
79 | dws->num_cs = 4; | 80 | dws->num_cs = 4; |
80 | dws->max_freq = clk_get_rate(dwsmmio->clk); | 81 | dws->max_freq = clk_get_rate(dwsmmio->clk); |
81 | 82 | ||
82 | ret = dw_spi_add_host(dws); | 83 | ret = dw_spi_add_host(dws); |
83 | if (ret) | 84 | if (ret) |
84 | goto err_clk; | 85 | goto err_clk; |
85 | 86 | ||
86 | platform_set_drvdata(pdev, dwsmmio); | 87 | platform_set_drvdata(pdev, dwsmmio); |
87 | return 0; | 88 | return 0; |
88 | 89 | ||
89 | err_clk: | 90 | err_clk: |
90 | clk_disable(dwsmmio->clk); | 91 | clk_disable(dwsmmio->clk); |
91 | clk_put(dwsmmio->clk); | 92 | clk_put(dwsmmio->clk); |
92 | dwsmmio->clk = NULL; | 93 | dwsmmio->clk = NULL; |
93 | err_irq: | 94 | err_irq: |
94 | free_irq(dws->irq, dws); | 95 | free_irq(dws->irq, dws); |
95 | err_unmap: | 96 | err_unmap: |
96 | iounmap(dws->regs); | 97 | iounmap(dws->regs); |
97 | err_release_reg: | 98 | err_release_reg: |
98 | release_mem_region(mem->start, resource_size(mem)); | 99 | release_mem_region(mem->start, resource_size(mem)); |
99 | err_kfree: | 100 | err_kfree: |
100 | kfree(dwsmmio); | 101 | kfree(dwsmmio); |
101 | err_end: | 102 | err_end: |
102 | return ret; | 103 | return ret; |
103 | } | 104 | } |
104 | 105 | ||
105 | static int __devexit dw_spi_mmio_remove(struct platform_device *pdev) | 106 | static int __devexit dw_spi_mmio_remove(struct platform_device *pdev) |
106 | { | 107 | { |
107 | struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); | 108 | struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); |
108 | struct resource *mem; | 109 | struct resource *mem; |
109 | 110 | ||
110 | platform_set_drvdata(pdev, NULL); | 111 | platform_set_drvdata(pdev, NULL); |
111 | 112 | ||
112 | clk_disable(dwsmmio->clk); | 113 | clk_disable(dwsmmio->clk); |
113 | clk_put(dwsmmio->clk); | 114 | clk_put(dwsmmio->clk); |
114 | dwsmmio->clk = NULL; | 115 | dwsmmio->clk = NULL; |
115 | 116 | ||
116 | free_irq(dwsmmio->dws.irq, &dwsmmio->dws); | 117 | free_irq(dwsmmio->dws.irq, &dwsmmio->dws); |
117 | dw_spi_remove_host(&dwsmmio->dws); | 118 | dw_spi_remove_host(&dwsmmio->dws); |
118 | iounmap(dwsmmio->dws.regs); | 119 | iounmap(dwsmmio->dws.regs); |
119 | kfree(dwsmmio); | 120 | kfree(dwsmmio); |
120 | 121 | ||
121 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 122 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
122 | release_mem_region(mem->start, resource_size(mem)); | 123 | release_mem_region(mem->start, resource_size(mem)); |
123 | return 0; | 124 | return 0; |
124 | } | 125 | } |
125 | 126 | ||
126 | static struct platform_driver dw_spi_mmio_driver = { | 127 | static struct platform_driver dw_spi_mmio_driver = { |
127 | .remove = __devexit_p(dw_spi_mmio_remove), | 128 | .remove = __devexit_p(dw_spi_mmio_remove), |
128 | .driver = { | 129 | .driver = { |
129 | .name = DRIVER_NAME, | 130 | .name = DRIVER_NAME, |
130 | .owner = THIS_MODULE, | 131 | .owner = THIS_MODULE, |
131 | }, | 132 | }, |
132 | }; | 133 | }; |
133 | 134 | ||
134 | static int __init dw_spi_mmio_init(void) | 135 | static int __init dw_spi_mmio_init(void) |
135 | { | 136 | { |
136 | return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe); | 137 | return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe); |
137 | } | 138 | } |
138 | module_init(dw_spi_mmio_init); | 139 | module_init(dw_spi_mmio_init); |
139 | 140 | ||
140 | static void __exit dw_spi_mmio_exit(void) | 141 | static void __exit dw_spi_mmio_exit(void) |
141 | { | 142 | { |
142 | platform_driver_unregister(&dw_spi_mmio_driver); | 143 | platform_driver_unregister(&dw_spi_mmio_driver); |
143 | } | 144 | } |
144 | module_exit(dw_spi_mmio_exit); | 145 | module_exit(dw_spi_mmio_exit); |
145 | 146 | ||
146 | MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>"); | 147 | MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>"); |
147 | MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); | 148 | MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); |
148 | MODULE_LICENSE("GPL v2"); | 149 | MODULE_LICENSE("GPL v2"); |
149 | 150 |