First git repo commit for the libreCMC project
[librecmc/librecmc.git] / target / linux / sunxi / patches-4.4 / 143-reset-add-shared-resetcontrol-asserts.patch
1 From d25cfe9b4f9663216ce4e011e3f1e7fa669ab58a Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Fri, 27 Nov 2015 21:09:05 +0100
4 Subject: [PATCH] reset: Add shared reset_control_[de]assert variants
5
6 Add reset_control_deassert_shared / reset_control_assert_shared
7 functions which are intended for use by drivers for hw blocks which
8 (may) share a reset line with another driver / hw block.
9
10 Unlike the regular reset_control_[de]assert functions these functions
11 keep track of how often deassert_shared / assert_shared have been called
12 and keep the line deasserted as long as deassert has been called more
13 times than assert.
14
15 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
16 ---
17 Changes in v2:
18 -This is a new patch in v2 of this patch-set
19 ---
20  drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
21  include/linux/reset-controller.h |   2 +
22  include/linux/reset.h            |   2 +
23  3 files changed, 116 insertions(+), 9 deletions(-)
24
25 --- a/drivers/reset/core.c
26 +++ b/drivers/reset/core.c
27 @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_lis
28  static LIST_HEAD(reset_controller_list);
29  
30  /**
31 + * struct reset_line - a reset line
32 + * @list:         list entry for the reset controllers reset line list
33 + * @id:           ID of the reset line in the reset controller device
34 + * @refcnt:       Number of reset_control structs referencing this device
35 + * @deassert_cnt: Number of times this reset line has been deasserted
36 + */
37 +struct reset_line {
38 +       struct list_head list;
39 +       unsigned int id;
40 +       unsigned int refcnt;
41 +       unsigned int deassert_cnt;
42 +};
43 +
44 +/**
45   * struct reset_control - a reset control
46   * @rcdev: a pointer to the reset controller device
47   *         this reset control belongs to
48 - * @id: ID of the reset controller in the reset
49 - *      controller device
50 + * @line:  reset line for this reset control
51   */
52  struct reset_control {
53         struct reset_controller_dev *rcdev;
54 +       struct reset_line *line;
55         struct device *dev;
56 -       unsigned int id;
57  };
58  
59  /**
60 @@ -66,6 +79,8 @@ int reset_controller_register(struct res
61                 rcdev->of_xlate = of_reset_simple_xlate;
62         }
63  
64 +       INIT_LIST_HEAD(&rcdev->reset_line_head);
65 +
66         mutex_lock(&reset_controller_list_mutex);
67         list_add(&rcdev->list, &reset_controller_list);
68         mutex_unlock(&reset_controller_list_mutex);
69 @@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unreg
70  int reset_control_reset(struct reset_control *rstc)
71  {
72         if (rstc->rcdev->ops->reset)
73 -               return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
74 +               return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
75  
76         return -ENOTSUPP;
77  }
78 @@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
79  int reset_control_assert(struct reset_control *rstc)
80  {
81         if (rstc->rcdev->ops->assert)
82 -               return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
83 +               return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
84  
85         return -ENOTSUPP;
86  }
87 @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
88  int reset_control_deassert(struct reset_control *rstc)
89  {
90         if (rstc->rcdev->ops->deassert)
91 -               return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
92 +               return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
93  
94         return -ENOTSUPP;
95  }
96  EXPORT_SYMBOL_GPL(reset_control_deassert);
97  
98  /**
99 + * reset_control_assert_shared - asserts a shared reset line
100 + * @rstc: reset controller
101 + *
102 + * Assert a shared reset line, this functions decreases the deassert count
103 + * of the line by one and asserts it if, and only if, the deassert count
104 + * reaches 0.
105 + */
106 +int reset_control_assert_shared(struct reset_control *rstc)
107 +{
108 +       if (!rstc->rcdev->ops->assert)
109 +               return -ENOTSUPP;
110 +
111 +       rstc->line->deassert_cnt--;
112 +       if (rstc->line->deassert_cnt)
113 +               return 0;
114 +
115 +       return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
116 +}
117 +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
118 +
119 +/**
120 + * reset_control_deassert_shared - deasserts a shared reset line
121 + * @rstc: reset controller
122 + *
123 + * Assert a shared reset line, this functions increases the deassert count
124 + * of the line by one and deasserts the reset line (if it was not already
125 + * deasserted).
126 + */
127 +int reset_control_deassert_shared(struct reset_control *rstc)
128 +{
129 +       if (!rstc->rcdev->ops->deassert)
130 +               return -ENOTSUPP;
131 +
132 +       rstc->line->deassert_cnt++;
133 +       if (rstc->line->deassert_cnt != 1)
134 +               return 0;
135 +
136 +       return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
137 +}
138 +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
139 +
140 +/**
141   * reset_control_status - returns a negative errno if not supported, a
142   * positive value if the reset line is asserted, or zero if the reset
143   * line is not asserted.
144 @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert
145  int reset_control_status(struct reset_control *rstc)
146  {
147         if (rstc->rcdev->ops->status)
148 -               return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
149 +               return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
150  
151         return -ENOTSUPP;
152  }
153  EXPORT_SYMBOL_GPL(reset_control_status);
154  
155 +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
156 +                                        unsigned int index)
157 +{
158 +       struct reset_line *line;
159 +
160 +       list_for_each_entry(line, &rcdev->reset_line_head, list) {
161 +               if (line->id == index) {
162 +                       line->refcnt++;
163 +                       return line;
164 +               }
165 +       }
166 +
167 +       line = kzalloc(sizeof(*line), GFP_KERNEL);
168 +       if (!line)
169 +               return NULL;
170 +
171 +       list_add(&line->list, &rcdev->reset_line_head);
172 +       line->id = index;
173 +       line->refcnt = 1;
174 +
175 +       return line;
176 +}
177 +
178 +static void reset_line_put(struct reset_line *line)
179 +{
180 +       if (!line)
181 +               return;
182 +
183 +       if (--line->refcnt)
184 +               return;
185 +
186 +       list_del(&line->list);
187 +       kfree(line);
188 +}
189 +
190  /**
191   * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
192   * controller by index.
193 @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_g
194  {
195         struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
196         struct reset_controller_dev *r, *rcdev;
197 +       struct reset_line *line;
198         struct of_phandle_args args;
199         int rstc_id;
200         int ret;
201 @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_g
202         }
203  
204         try_module_get(rcdev->owner);
205 +
206 +       /* reset_controller_list_mutex also protects the reset_line list */
207 +       line = reset_line_get(rcdev, rstc_id);
208 +
209         mutex_unlock(&reset_controller_list_mutex);
210  
211         rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
212 -       if (!rstc) {
213 +       if (!line || !rstc) {
214 +               kfree(rstc);
215 +               reset_line_put(line);
216                 module_put(rcdev->owner);
217                 return ERR_PTR(-ENOMEM);
218         }
219  
220         rstc->rcdev = rcdev;
221 -       rstc->id = rstc_id;
222 +       rstc->line = line;
223  
224         return rstc;
225  }
226 @@ -259,6 +358,10 @@ void reset_control_put(struct reset_cont
227         if (IS_ERR(rstc))
228                 return;
229  
230 +       mutex_lock(&reset_controller_list_mutex);
231 +       reset_line_put(rstc->line);
232 +       mutex_unlock(&reset_controller_list_mutex);
233 +
234         module_put(rstc->rcdev->owner);
235         kfree(rstc);
236  }
237 --- a/include/linux/reset-controller.h
238 +++ b/include/linux/reset-controller.h
239 @@ -31,6 +31,7 @@ struct of_phandle_args;
240   * @ops: a pointer to device specific struct reset_control_ops
241   * @owner: kernel module of the reset controller driver
242   * @list: internal list of reset controller devices
243 + * @reset_line_head: head of internal list of reset lines
244   * @of_node: corresponding device tree node as phandle target
245   * @of_reset_n_cells: number of cells in reset line specifiers
246   * @of_xlate: translation function to translate from specifier as found in the
247 @@ -41,6 +42,7 @@ struct reset_controller_dev {
248         struct reset_control_ops *ops;
249         struct module *owner;
250         struct list_head list;
251 +       struct list_head reset_line_head;
252         struct device_node *of_node;
253         int of_reset_n_cells;
254         int (*of_xlate)(struct reset_controller_dev *rcdev,
255 --- a/include/linux/reset.h
256 +++ b/include/linux/reset.h
257 @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_con
258  int reset_control_assert(struct reset_control *rstc);
259  int reset_control_deassert(struct reset_control *rstc);
260  int reset_control_status(struct reset_control *rstc);
261 +int reset_control_assert_shared(struct reset_control *rstc);
262 +int reset_control_deassert_shared(struct reset_control *rstc);
263  
264  struct reset_control *reset_control_get(struct device *dev, const char *id);
265  void reset_control_put(struct reset_control *rstc);