diff options
Diffstat (limited to 'drivers/misc/atmel_tclib.c')
-rw-r--r-- | drivers/misc/atmel_tclib.c | 101 |
1 files changed, 44 insertions, 57 deletions
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index c8d8e38d0d8a..0ca05c3ec8d6 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,25 +108,27 @@ 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)) | 112 | unsigned int i; |
147 | return -EINVAL; | ||
148 | 113 | ||
149 | irq = platform_get_irq(pdev, 0); | 114 | irq = platform_get_irq(pdev, 0); |
150 | if (irq < 0) | 115 | if (irq < 0) |
151 | return -EINVAL; | 116 | return -EINVAL; |
152 | 117 | ||
153 | tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL); | 118 | tc = devm_kzalloc(&pdev->dev, sizeof(struct atmel_tc), GFP_KERNEL); |
154 | if (!tc) | 119 | if (!tc) |
155 | return -ENOMEM; | 120 | return -ENOMEM; |
156 | 121 | ||
157 | tc->pdev = pdev; | 122 | tc->pdev = pdev; |
158 | 123 | ||
159 | clk = clk_get(&pdev->dev, "t0_clk"); | 124 | clk = devm_clk_get(&pdev->dev, "t0_clk"); |
160 | if (IS_ERR(clk)) { | 125 | if (IS_ERR(clk)) |
161 | kfree(tc); | 126 | return PTR_ERR(clk); |
162 | return -EINVAL; | 127 | |
163 | } | 128 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
129 | tc->regs = devm_ioremap_resource(&pdev->dev, r); | ||
130 | if (IS_ERR(tc->regs)) | ||
131 | return PTR_ERR(tc->regs); | ||
164 | 132 | ||
165 | /* Now take SoC information if available */ | 133 | /* Now take SoC information if available */ |
166 | if (pdev->dev.of_node) { | 134 | if (pdev->dev.of_node) { |
@@ -168,13 +136,17 @@ static int __init tc_probe(struct platform_device *pdev) | |||
168 | match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node); | 136 | match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node); |
169 | if (match) | 137 | if (match) |
170 | tc->tcb_config = match->data; | 138 | tc->tcb_config = match->data; |
139 | |||
140 | tc->id = of_alias_get_id(tc->pdev->dev.of_node, "tcb"); | ||
141 | } else { | ||
142 | tc->id = pdev->id; | ||
171 | } | 143 | } |
172 | 144 | ||
173 | tc->clk[0] = clk; | 145 | tc->clk[0] = clk; |
174 | tc->clk[1] = clk_get(&pdev->dev, "t1_clk"); | 146 | tc->clk[1] = devm_clk_get(&pdev->dev, "t1_clk"); |
175 | if (IS_ERR(tc->clk[1])) | 147 | if (IS_ERR(tc->clk[1])) |
176 | tc->clk[1] = clk; | 148 | tc->clk[1] = clk; |
177 | tc->clk[2] = clk_get(&pdev->dev, "t2_clk"); | 149 | tc->clk[2] = devm_clk_get(&pdev->dev, "t2_clk"); |
178 | if (IS_ERR(tc->clk[2])) | 150 | if (IS_ERR(tc->clk[2])) |
179 | tc->clk[2] = clk; | 151 | tc->clk[2] = clk; |
180 | 152 | ||
@@ -186,18 +158,33 @@ static int __init tc_probe(struct platform_device *pdev) | |||
186 | if (tc->irq[2] < 0) | 158 | if (tc->irq[2] < 0) |
187 | tc->irq[2] = irq; | 159 | tc->irq[2] = irq; |
188 | 160 | ||
161 | for (i = 0; i < 3; i++) | ||
162 | writel(ATMEL_TC_ALL_IRQ, tc->regs + ATMEL_TC_REG(i, IDR)); | ||
163 | |||
189 | spin_lock(&tc_list_lock); | 164 | spin_lock(&tc_list_lock); |
190 | list_add_tail(&tc->node, &tc_list); | 165 | list_add_tail(&tc->node, &tc_list); |
191 | spin_unlock(&tc_list_lock); | 166 | spin_unlock(&tc_list_lock); |
192 | 167 | ||
168 | platform_set_drvdata(pdev, tc); | ||
169 | |||
193 | return 0; | 170 | return 0; |
194 | } | 171 | } |
195 | 172 | ||
173 | static void tc_shutdown(struct platform_device *pdev) | ||
174 | { | ||
175 | int i; | ||
176 | struct atmel_tc *tc = platform_get_drvdata(pdev); | ||
177 | |||
178 | for (i = 0; i < 3; i++) | ||
179 | writel(ATMEL_TC_ALL_IRQ, tc->regs + ATMEL_TC_REG(i, IDR)); | ||
180 | } | ||
181 | |||
196 | static struct platform_driver tc_driver = { | 182 | static struct platform_driver tc_driver = { |
197 | .driver = { | 183 | .driver = { |
198 | .name = "atmel_tcb", | 184 | .name = "atmel_tcb", |
199 | .of_match_table = of_match_ptr(atmel_tcb_dt_ids), | 185 | .of_match_table = of_match_ptr(atmel_tcb_dt_ids), |
200 | }, | 186 | }, |
187 | .shutdown = tc_shutdown, | ||
201 | }; | 188 | }; |
202 | 189 | ||
203 | static int __init tc_init(void) | 190 | static int __init tc_init(void) |