diff options
Diffstat (limited to 'drivers/misc/atmel_tclib.c')
-rw-r--r-- | drivers/misc/atmel_tclib.c | 71 |
1 files changed, 22 insertions, 49 deletions
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index b514a2d4485b..d505d1e0857b 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c | |||
@@ -35,60 +35,31 @@ static LIST_HEAD(tc_list); | |||
35 | /** | 35 | /** |
36 | * atmel_tc_alloc - allocate a specified TC block | 36 | * atmel_tc_alloc - allocate a specified TC block |
37 | * @block: which block to allocate | 37 | * @block: which block to allocate |
38 | * @name: name to be associated with the iomem resource | ||
39 | * | 38 | * |
40 | * Caller allocates a block. If it is available, a pointer to a | 39 | * Caller allocates a block. If it is available, a pointer to a |
41 | * pre-initialized struct atmel_tc is returned. The caller can access | 40 | * pre-initialized struct atmel_tc is returned. The caller can access |
42 | * the registers directly through the "regs" field. | 41 | * the registers directly through the "regs" field. |
43 | */ | 42 | */ |
44 | struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) | 43 | struct atmel_tc *atmel_tc_alloc(unsigned block) |
45 | { | 44 | { |
46 | struct atmel_tc *tc; | 45 | struct atmel_tc *tc; |
47 | struct platform_device *pdev = NULL; | 46 | struct platform_device *pdev = NULL; |
48 | struct resource *r; | ||
49 | size_t size; | ||
50 | 47 | ||
51 | spin_lock(&tc_list_lock); | 48 | spin_lock(&tc_list_lock); |
52 | list_for_each_entry(tc, &tc_list, node) { | 49 | list_for_each_entry(tc, &tc_list, node) { |
53 | if (tc->pdev->dev.of_node) { | 50 | if (tc->allocated) |
54 | if (of_alias_get_id(tc->pdev->dev.of_node, "tcb") | 51 | continue; |
55 | == block) { | 52 | |
56 | pdev = tc->pdev; | 53 | if ((tc->pdev->dev.of_node && tc->id == block) || |
57 | break; | 54 | (tc->pdev->id == block)) { |
58 | } | ||
59 | } else if (tc->pdev->id == block) { | ||
60 | pdev = tc->pdev; | 55 | pdev = tc->pdev; |
56 | tc->allocated = true; | ||
61 | break; | 57 | break; |
62 | } | 58 | } |
63 | } | 59 | } |
64 | |||
65 | if (!pdev || tc->iomem) | ||
66 | goto fail; | ||
67 | |||
68 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
69 | if (!r) | ||
70 | goto fail; | ||
71 | |||
72 | size = resource_size(r); | ||
73 | r = request_mem_region(r->start, size, name); | ||
74 | if (!r) | ||
75 | goto fail; | ||
76 | |||
77 | tc->regs = ioremap(r->start, size); | ||
78 | if (!tc->regs) | ||
79 | goto fail_ioremap; | ||
80 | |||
81 | tc->iomem = r; | ||
82 | |||
83 | out: | ||
84 | spin_unlock(&tc_list_lock); | 60 | spin_unlock(&tc_list_lock); |
85 | return tc; | ||
86 | 61 | ||
87 | fail_ioremap: | 62 | return pdev ? tc : NULL; |
88 | release_mem_region(r->start, size); | ||
89 | fail: | ||
90 | tc = NULL; | ||
91 | goto out; | ||
92 | } | 63 | } |
93 | EXPORT_SYMBOL_GPL(atmel_tc_alloc); | 64 | EXPORT_SYMBOL_GPL(atmel_tc_alloc); |
94 | 65 | ||
@@ -96,19 +67,14 @@ EXPORT_SYMBOL_GPL(atmel_tc_alloc); | |||
96 | * atmel_tc_free - release a specified TC block | 67 | * atmel_tc_free - release a specified TC block |
97 | * @tc: Timer/counter block that was returned by atmel_tc_alloc() | 68 | * @tc: Timer/counter block that was returned by atmel_tc_alloc() |
98 | * | 69 | * |
99 | * This reverses the effect of atmel_tc_alloc(), unmapping the I/O | 70 | * This reverses the effect of atmel_tc_alloc(), invalidating the resource |
100 | * registers, invalidating the resource returned by that routine and | 71 | * returned by that routine and making the TC available to other drivers. |
101 | * making the TC available to other drivers. | ||
102 | */ | 72 | */ |
103 | void atmel_tc_free(struct atmel_tc *tc) | 73 | void atmel_tc_free(struct atmel_tc *tc) |
104 | { | 74 | { |
105 | spin_lock(&tc_list_lock); | 75 | spin_lock(&tc_list_lock); |
106 | if (tc->regs) { | 76 | if (tc->allocated) |
107 | iounmap(tc->regs); | 77 | tc->allocated = false; |
108 | release_mem_region(tc->iomem->start, resource_size(tc->iomem)); | ||
109 | tc->regs = NULL; | ||
110 | tc->iomem = NULL; | ||
111 | } | ||
112 | spin_unlock(&tc_list_lock); | 78 | spin_unlock(&tc_list_lock); |
113 | } | 79 | } |
114 | EXPORT_SYMBOL_GPL(atmel_tc_free); | 80 | EXPORT_SYMBOL_GPL(atmel_tc_free); |
@@ -142,9 +108,7 @@ static int __init tc_probe(struct platform_device *pdev) | |||
142 | struct atmel_tc *tc; | 108 | struct atmel_tc *tc; |
143 | struct clk *clk; | 109 | struct clk *clk; |
144 | int irq; | 110 | int irq; |
145 | 111 | struct resource *r; | |
146 | if (!platform_get_resource(pdev, IORESOURCE_MEM, 0)) | ||
147 | return -EINVAL; | ||
148 | 112 | ||
149 | irq = platform_get_irq(pdev, 0); | 113 | irq = platform_get_irq(pdev, 0); |
150 | if (irq < 0) | 114 | if (irq < 0) |
@@ -160,12 +124,21 @@ static int __init tc_probe(struct platform_device *pdev) | |||
160 | if (IS_ERR(clk)) | 124 | if (IS_ERR(clk)) |
161 | return PTR_ERR(clk); | 125 | return PTR_ERR(clk); |
162 | 126 | ||
127 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
128 | tc->regs = devm_ioremap_resource(&pdev->dev, r); | ||
129 | if (IS_ERR(tc->regs)) | ||
130 | return PTR_ERR(tc->regs); | ||
131 | |||
163 | /* Now take SoC information if available */ | 132 | /* Now take SoC information if available */ |
164 | if (pdev->dev.of_node) { | 133 | if (pdev->dev.of_node) { |
165 | const struct of_device_id *match; | 134 | const struct of_device_id *match; |
166 | match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node); | 135 | match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node); |
167 | if (match) | 136 | if (match) |
168 | tc->tcb_config = match->data; | 137 | tc->tcb_config = match->data; |
138 | |||
139 | tc->id = of_alias_get_id(tc->pdev->dev.of_node, "tcb"); | ||
140 | } else { | ||
141 | tc->id = pdev->id; | ||
169 | } | 142 | } |
170 | 143 | ||
171 | tc->clk[0] = clk; | 144 | tc->clk[0] = clk; |