Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

reset: Add support for shared reset controls

In some SoCs some hw-blocks share a reset control. Add support for this
setup by adding new:

reset_control_get_shared()
devm_reset_control_get_shared()
devm_reset_control_get_shared_by_index()

methods to get a reset_control. Note that this patch omits adding of_
variants, if these are needed later they can be easily added.

This patch also changes the behavior of the existing exclusive
reset_control_get() variants, if these are now called more then once
for the same reset_control they will return -EBUSY. To catch existing
drivers triggering this error (there should not be any) a WARN_ON(1)
is added in this path.

When a reset_control is shared, the behavior of reset_control_assert /
deassert is changed, for shared reset_controls these will work like the
clock-enable/disable and regulator-on/off functions. They will keep a
deassert_count, and only (re-)assert the reset after reset_control_assert
has been called as many times as reset_control_deassert was called.

Calling reset_control_assert without first calling reset_control_deassert
is not allowed on a shared reset control. Calling reset_control_reset is
also not allowed on a shared reset control.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Hans de Goede and committed by
Philipp Zabel
0b52297f c15ddec2

+129 -26
+48 -11
drivers/reset/core.c
··· 8 8 * the Free Software Foundation; either version 2 of the License, or 9 9 * (at your option) any later version. 10 10 */ 11 + #include <linux/atomic.h> 11 12 #include <linux/device.h> 12 13 #include <linux/err.h> 13 14 #include <linux/export.h> ··· 30 29 * @id: ID of the reset controller in the reset 31 30 * controller device 32 31 * @refcnt: Number of gets of this reset_control 32 + * @shared: Is this a shared (1), or an exclusive (0) reset_control? 33 + * @deassert_cnt: Number of times this reset line has been deasserted 33 34 */ 34 35 struct reset_control { 35 36 struct reset_controller_dev *rcdev; 36 37 struct list_head list; 37 38 unsigned int id; 38 39 unsigned int refcnt; 40 + int shared; 41 + atomic_t deassert_count; 39 42 }; 40 43 41 44 /** ··· 96 91 /** 97 92 * reset_control_reset - reset the controlled device 98 93 * @rstc: reset controller 94 + * 95 + * Calling this on a shared reset controller is an error. 99 96 */ 100 97 int reset_control_reset(struct reset_control *rstc) 101 98 { 99 + if (WARN_ON(rstc->shared)) 100 + return -EINVAL; 101 + 102 102 if (rstc->rcdev->ops->reset) 103 103 return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); 104 104 ··· 114 104 /** 115 105 * reset_control_assert - asserts the reset line 116 106 * @rstc: reset controller 107 + * 108 + * Calling this on an exclusive reset controller guarantees that the reset 109 + * will be asserted. When called on a shared reset controller the line may 110 + * still be deasserted, as long as other users keep it so. 111 + * 112 + * For shared reset controls a driver cannot expect the hw's registers and 113 + * internal state to be reset, but must be prepared for this to happen. 117 114 */ 118 115 int reset_control_assert(struct reset_control *rstc) 119 116 { 120 - if (rstc->rcdev->ops->assert) 121 - return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); 117 + if (!rstc->rcdev->ops->assert) 118 + return -ENOTSUPP; 122 119 123 - return -ENOTSUPP; 120 + if (rstc->shared) { 121 + if (WARN_ON(atomic_read(&rstc->deassert_count) == 0)) 122 + return -EINVAL; 123 + 124 + if (atomic_dec_return(&rstc->deassert_count) != 0) 125 + return 0; 126 + } 127 + 128 + return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); 124 129 } 125 130 EXPORT_SYMBOL_GPL(reset_control_assert); 126 131 127 132 /** 128 133 * reset_control_deassert - deasserts the reset line 129 134 * @rstc: reset controller 135 + * 136 + * After calling this function, the reset is guaranteed to be deasserted. 130 137 */ 131 138 int reset_control_deassert(struct reset_control *rstc) 132 139 { 133 - if (rstc->rcdev->ops->deassert) 134 - return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); 140 + if (!rstc->rcdev->ops->deassert) 141 + return -ENOTSUPP; 135 142 136 - return -ENOTSUPP; 143 + if (rstc->shared) { 144 + if (atomic_inc_return(&rstc->deassert_count) != 1) 145 + return 0; 146 + } 147 + 148 + return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); 137 149 } 138 150 EXPORT_SYMBOL_GPL(reset_control_deassert); 139 151 ··· 176 144 177 145 static struct reset_control *__reset_control_get( 178 146 struct reset_controller_dev *rcdev, 179 - unsigned int index) 147 + unsigned int index, int shared) 180 148 { 181 149 struct reset_control *rstc; 182 150 ··· 184 152 185 153 list_for_each_entry(rstc, &rcdev->reset_control_head, list) { 186 154 if (rstc->id == index) { 155 + if (WARN_ON(!rstc->shared || !shared)) 156 + return ERR_PTR(-EBUSY); 157 + 187 158 rstc->refcnt++; 188 159 return rstc; 189 160 } ··· 202 167 list_add(&rstc->list, &rcdev->reset_control_head); 203 168 rstc->id = index; 204 169 rstc->refcnt = 1; 170 + rstc->shared = shared; 205 171 206 172 return rstc; 207 173 } ··· 221 185 } 222 186 223 187 struct reset_control *__of_reset_control_get(struct device_node *node, 224 - const char *id, int index) 188 + const char *id, int index, int shared) 225 189 { 226 190 struct reset_control *rstc; 227 191 struct reset_controller_dev *r, *rcdev; ··· 271 235 } 272 236 273 237 /* reset_list_mutex also protects the rcdev's reset_control list */ 274 - rstc = __reset_control_get(rcdev, rstc_id); 238 + rstc = __reset_control_get(rcdev, rstc_id, shared); 275 239 276 240 mutex_unlock(&reset_list_mutex); 277 241 ··· 301 265 } 302 266 303 267 struct reset_control *__devm_reset_control_get(struct device *dev, 304 - const char *id, int index) 268 + const char *id, int index, int shared) 305 269 { 306 270 struct reset_control **ptr, *rstc; 307 271 ··· 310 274 if (!ptr) 311 275 return ERR_PTR(-ENOMEM); 312 276 313 - rstc = __of_reset_control_get(dev ? dev->of_node : NULL, id, index); 277 + rstc = __of_reset_control_get(dev ? dev->of_node : NULL, 278 + id, index, shared); 314 279 if (!IS_ERR(rstc)) { 315 280 *ptr = rstc; 316 281 devres_add(dev, ptr);
+81 -15
include/linux/reset.h
··· 13 13 int reset_control_status(struct reset_control *rstc); 14 14 15 15 struct reset_control *__of_reset_control_get(struct device_node *node, 16 - const char *id, int index); 16 + const char *id, int index, int shared); 17 17 void reset_control_put(struct reset_control *rstc); 18 18 struct reset_control *__devm_reset_control_get(struct device *dev, 19 - const char *id, int index); 19 + const char *id, int index, int shared); 20 20 21 21 int __must_check device_reset(struct device *dev); 22 22 ··· 63 63 64 64 static inline struct reset_control *__of_reset_control_get( 65 65 struct device_node *node, 66 - const char *id, int index) 66 + const char *id, int index, int shared) 67 67 { 68 68 return ERR_PTR(-EINVAL); 69 69 } 70 70 71 71 static inline struct reset_control *__devm_reset_control_get( 72 72 struct device *dev, 73 - const char *id, int index) 73 + const char *id, int index, int shared) 74 74 { 75 75 return ERR_PTR(-EINVAL); 76 76 } ··· 78 78 #endif /* CONFIG_RESET_CONTROLLER */ 79 79 80 80 /** 81 - * reset_control_get - Lookup and obtain a reference to a reset controller. 81 + * reset_control_get - Lookup and obtain an exclusive reference to a 82 + * reset controller. 82 83 * @dev: device to be reset by the controller 83 84 * @id: reset line name 84 85 * 85 86 * Returns a struct reset_control or IS_ERR() condition containing errno. 87 + * If this function is called more then once for the same reset_control it will 88 + * return -EBUSY. 89 + * 90 + * See reset_control_get_shared for details on shared references to 91 + * reset-controls. 86 92 * 87 93 * Use of id names is optional. 88 94 */ ··· 98 92 #ifndef CONFIG_RESET_CONTROLLER 99 93 WARN_ON(1); 100 94 #endif 101 - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0); 95 + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0); 102 96 } 103 97 104 98 static inline struct reset_control *reset_control_get_optional( 105 99 struct device *dev, const char *id) 106 100 { 107 - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0); 101 + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0); 108 102 } 109 103 110 104 /** 111 - * of_reset_control_get - Lookup and obtain a reference to a reset controller. 105 + * reset_control_get_shared - Lookup and obtain a shared reference to a 106 + * reset controller. 107 + * @dev: device to be reset by the controller 108 + * @id: reset line name 109 + * 110 + * Returns a struct reset_control or IS_ERR() condition containing errno. 111 + * This function is intended for use with reset-controls which are shared 112 + * between hardware-blocks. 113 + * 114 + * When a reset-control is shared, the behavior of reset_control_assert / 115 + * deassert is changed, the reset-core will keep track of a deassert_count 116 + * and only (re-)assert the reset after reset_control_assert has been called 117 + * as many times as reset_control_deassert was called. Also see the remark 118 + * about shared reset-controls in the reset_control_assert docs. 119 + * 120 + * Calling reset_control_assert without first calling reset_control_deassert 121 + * is not allowed on a shared reset control. Calling reset_control_reset is 122 + * also not allowed on a shared reset control. 123 + * 124 + * Use of id names is optional. 125 + */ 126 + static inline struct reset_control *reset_control_get_shared( 127 + struct device *dev, const char *id) 128 + { 129 + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1); 130 + } 131 + 132 + /** 133 + * of_reset_control_get - Lookup and obtain an exclusive reference to a 134 + * reset controller. 112 135 * @node: device to be reset by the controller 113 136 * @id: reset line name 114 137 * ··· 148 113 static inline struct reset_control *of_reset_control_get( 149 114 struct device_node *node, const char *id) 150 115 { 151 - return __of_reset_control_get(node, id, 0); 116 + return __of_reset_control_get(node, id, 0, 0); 152 117 } 153 118 154 119 /** 155 - * of_reset_control_get_by_index - Lookup and obtain a reference to a reset 156 - * controller by index. 120 + * of_reset_control_get_by_index - Lookup and obtain an exclusive reference to 121 + * a reset controller by index. 157 122 * @node: device to be reset by the controller 158 123 * @index: index of the reset controller 159 124 * ··· 164 129 static inline struct reset_control *of_reset_control_get_by_index( 165 130 struct device_node *node, int index) 166 131 { 167 - return __of_reset_control_get(node, NULL, index); 132 + return __of_reset_control_get(node, NULL, index, 0); 168 133 } 169 134 170 135 /** ··· 182 147 #ifndef CONFIG_RESET_CONTROLLER 183 148 WARN_ON(1); 184 149 #endif 185 - return __devm_reset_control_get(dev, id, 0); 150 + return __devm_reset_control_get(dev, id, 0, 0); 186 151 } 187 152 188 153 static inline struct reset_control *devm_reset_control_get_optional( 189 154 struct device *dev, const char *id) 190 155 { 191 - return __devm_reset_control_get(dev, id, 0); 156 + return __devm_reset_control_get(dev, id, 0, 0); 192 157 } 193 158 194 159 /** ··· 203 168 static inline struct reset_control *devm_reset_control_get_by_index( 204 169 struct device *dev, int index) 205 170 { 206 - return __devm_reset_control_get(dev, NULL, index); 171 + return __devm_reset_control_get(dev, NULL, index, 0); 172 + } 173 + 174 + /** 175 + * devm_reset_control_get_shared - resource managed reset_control_get_shared() 176 + * @dev: device to be reset by the controller 177 + * @id: reset line name 178 + * 179 + * Managed reset_control_get_shared(). For reset controllers returned from 180 + * this function, reset_control_put() is called automatically on driver detach. 181 + * See reset_control_get_shared() for more information. 182 + */ 183 + static inline struct reset_control *devm_reset_control_get_shared( 184 + struct device *dev, const char *id) 185 + { 186 + return __devm_reset_control_get(dev, id, 0, 1); 187 + } 188 + 189 + /** 190 + * devm_reset_control_get_shared_by_index - resource managed 191 + * reset_control_get_shared 192 + * @dev: device to be reset by the controller 193 + * @index: index of the reset controller 194 + * 195 + * Managed reset_control_get_shared(). For reset controllers returned from 196 + * this function, reset_control_put() is called automatically on driver detach. 197 + * See reset_control_get_shared() for more information. 198 + */ 199 + static inline struct reset_control *devm_reset_control_get_shared_by_index( 200 + struct device *dev, int index) 201 + { 202 + return __devm_reset_control_get(dev, NULL, index, 1); 207 203 } 208 204 209 205 #endif