diff options
Diffstat (limited to 'drivers/reset/core.c')
| -rw-r--r-- | drivers/reset/core.c | 77 |
1 files changed, 58 insertions, 19 deletions
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 10368ed8fd13..cd739d2fa160 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c | |||
| @@ -41,7 +41,7 @@ struct reset_control { | |||
| 41 | struct list_head list; | 41 | struct list_head list; |
| 42 | unsigned int id; | 42 | unsigned int id; |
| 43 | unsigned int refcnt; | 43 | unsigned int refcnt; |
| 44 | int shared; | 44 | bool shared; |
| 45 | atomic_t deassert_count; | 45 | atomic_t deassert_count; |
| 46 | atomic_t triggered_count; | 46 | atomic_t triggered_count; |
| 47 | }; | 47 | }; |
| @@ -143,12 +143,18 @@ EXPORT_SYMBOL_GPL(devm_reset_controller_register); | |||
| 143 | * a no-op. | 143 | * a no-op. |
| 144 | * Consumers must not use reset_control_(de)assert on shared reset lines when | 144 | * Consumers must not use reset_control_(de)assert on shared reset lines when |
| 145 | * reset_control_reset has been used. | 145 | * reset_control_reset has been used. |
| 146 | * | ||
| 147 | * If rstc is NULL it is an optional reset and the function will just | ||
| 148 | * return 0. | ||
| 146 | */ | 149 | */ |
| 147 | int reset_control_reset(struct reset_control *rstc) | 150 | int reset_control_reset(struct reset_control *rstc) |
| 148 | { | 151 | { |
| 149 | int ret; | 152 | int ret; |
| 150 | 153 | ||
| 151 | if (WARN_ON(IS_ERR_OR_NULL(rstc))) | 154 | if (!rstc) |
| 155 | return 0; | ||
| 156 | |||
| 157 | if (WARN_ON(IS_ERR(rstc))) | ||
| 152 | return -EINVAL; | 158 | return -EINVAL; |
| 153 | 159 | ||
| 154 | if (!rstc->rcdev->ops->reset) | 160 | if (!rstc->rcdev->ops->reset) |
| @@ -163,7 +169,7 @@ int reset_control_reset(struct reset_control *rstc) | |||
| 163 | } | 169 | } |
| 164 | 170 | ||
| 165 | ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); | 171 | ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); |
| 166 | if (rstc->shared && !ret) | 172 | if (rstc->shared && ret) |
| 167 | atomic_dec(&rstc->triggered_count); | 173 | atomic_dec(&rstc->triggered_count); |
| 168 | 174 | ||
| 169 | return ret; | 175 | return ret; |
| @@ -182,10 +188,17 @@ EXPORT_SYMBOL_GPL(reset_control_reset); | |||
| 182 | * internal state to be reset, but must be prepared for this to happen. | 188 | * internal state to be reset, but must be prepared for this to happen. |
| 183 | * Consumers must not use reset_control_reset on shared reset lines when | 189 | * Consumers must not use reset_control_reset on shared reset lines when |
| 184 | * reset_control_(de)assert has been used. | 190 | * reset_control_(de)assert has been used. |
| 191 | * return 0. | ||
| 192 | * | ||
| 193 | * If rstc is NULL it is an optional reset and the function will just | ||
| 194 | * return 0. | ||
| 185 | */ | 195 | */ |
| 186 | int reset_control_assert(struct reset_control *rstc) | 196 | int reset_control_assert(struct reset_control *rstc) |
| 187 | { | 197 | { |
| 188 | if (WARN_ON(IS_ERR_OR_NULL(rstc))) | 198 | if (!rstc) |
| 199 | return 0; | ||
| 200 | |||
| 201 | if (WARN_ON(IS_ERR(rstc))) | ||
| 189 | return -EINVAL; | 202 | return -EINVAL; |
| 190 | 203 | ||
| 191 | if (!rstc->rcdev->ops->assert) | 204 | if (!rstc->rcdev->ops->assert) |
| @@ -213,10 +226,17 @@ EXPORT_SYMBOL_GPL(reset_control_assert); | |||
| 213 | * After calling this function, the reset is guaranteed to be deasserted. | 226 | * After calling this function, the reset is guaranteed to be deasserted. |
| 214 | * Consumers must not use reset_control_reset on shared reset lines when | 227 | * Consumers must not use reset_control_reset on shared reset lines when |
| 215 | * reset_control_(de)assert has been used. | 228 | * reset_control_(de)assert has been used. |
| 229 | * return 0. | ||
| 230 | * | ||
| 231 | * If rstc is NULL it is an optional reset and the function will just | ||
| 232 | * return 0. | ||
| 216 | */ | 233 | */ |
| 217 | int reset_control_deassert(struct reset_control *rstc) | 234 | int reset_control_deassert(struct reset_control *rstc) |
| 218 | { | 235 | { |
| 219 | if (WARN_ON(IS_ERR_OR_NULL(rstc))) | 236 | if (!rstc) |
| 237 | return 0; | ||
| 238 | |||
| 239 | if (WARN_ON(IS_ERR(rstc))) | ||
| 220 | return -EINVAL; | 240 | return -EINVAL; |
| 221 | 241 | ||
| 222 | if (!rstc->rcdev->ops->deassert) | 242 | if (!rstc->rcdev->ops->deassert) |
| @@ -237,12 +257,15 @@ EXPORT_SYMBOL_GPL(reset_control_deassert); | |||
| 237 | /** | 257 | /** |
| 238 | * reset_control_status - returns a negative errno if not supported, a | 258 | * reset_control_status - returns a negative errno if not supported, a |
| 239 | * positive value if the reset line is asserted, or zero if the reset | 259 | * positive value if the reset line is asserted, or zero if the reset |
| 240 | * line is not asserted. | 260 | * line is not asserted or if the desc is NULL (optional reset). |
| 241 | * @rstc: reset controller | 261 | * @rstc: reset controller |
| 242 | */ | 262 | */ |
| 243 | int reset_control_status(struct reset_control *rstc) | 263 | int reset_control_status(struct reset_control *rstc) |
| 244 | { | 264 | { |
| 245 | if (WARN_ON(IS_ERR_OR_NULL(rstc))) | 265 | if (!rstc) |
| 266 | return 0; | ||
| 267 | |||
| 268 | if (WARN_ON(IS_ERR(rstc))) | ||
| 246 | return -EINVAL; | 269 | return -EINVAL; |
| 247 | 270 | ||
| 248 | if (rstc->rcdev->ops->status) | 271 | if (rstc->rcdev->ops->status) |
| @@ -252,9 +275,9 @@ int reset_control_status(struct reset_control *rstc) | |||
| 252 | } | 275 | } |
| 253 | EXPORT_SYMBOL_GPL(reset_control_status); | 276 | EXPORT_SYMBOL_GPL(reset_control_status); |
| 254 | 277 | ||
| 255 | static struct reset_control *__reset_control_get( | 278 | static struct reset_control *__reset_control_get_internal( |
| 256 | struct reset_controller_dev *rcdev, | 279 | struct reset_controller_dev *rcdev, |
| 257 | unsigned int index, int shared) | 280 | unsigned int index, bool shared) |
| 258 | { | 281 | { |
| 259 | struct reset_control *rstc; | 282 | struct reset_control *rstc; |
| 260 | 283 | ||
| @@ -285,7 +308,7 @@ static struct reset_control *__reset_control_get( | |||
| 285 | return rstc; | 308 | return rstc; |
| 286 | } | 309 | } |
| 287 | 310 | ||
| 288 | static void __reset_control_put(struct reset_control *rstc) | 311 | static void __reset_control_put_internal(struct reset_control *rstc) |
| 289 | { | 312 | { |
| 290 | lockdep_assert_held(&reset_list_mutex); | 313 | lockdep_assert_held(&reset_list_mutex); |
| 291 | 314 | ||
| @@ -299,7 +322,8 @@ static void __reset_control_put(struct reset_control *rstc) | |||
| 299 | } | 322 | } |
| 300 | 323 | ||
| 301 | struct reset_control *__of_reset_control_get(struct device_node *node, | 324 | struct reset_control *__of_reset_control_get(struct device_node *node, |
| 302 | const char *id, int index, int shared) | 325 | const char *id, int index, bool shared, |
| 326 | bool optional) | ||
| 303 | { | 327 | { |
| 304 | struct reset_control *rstc; | 328 | struct reset_control *rstc; |
| 305 | struct reset_controller_dev *r, *rcdev; | 329 | struct reset_controller_dev *r, *rcdev; |
| @@ -313,14 +337,18 @@ struct reset_control *__of_reset_control_get(struct device_node *node, | |||
| 313 | if (id) { | 337 | if (id) { |
| 314 | index = of_property_match_string(node, | 338 | index = of_property_match_string(node, |
| 315 | "reset-names", id); | 339 | "reset-names", id); |
| 340 | if (index == -EILSEQ) | ||
| 341 | return ERR_PTR(index); | ||
| 316 | if (index < 0) | 342 | if (index < 0) |
| 317 | return ERR_PTR(-ENOENT); | 343 | return optional ? NULL : ERR_PTR(-ENOENT); |
| 318 | } | 344 | } |
| 319 | 345 | ||
| 320 | ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", | 346 | ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", |
| 321 | index, &args); | 347 | index, &args); |
| 322 | if (ret) | 348 | if (ret == -EINVAL) |
| 323 | return ERR_PTR(ret); | 349 | return ERR_PTR(ret); |
| 350 | if (ret) | ||
| 351 | return optional ? NULL : ERR_PTR(ret); | ||
| 324 | 352 | ||
| 325 | mutex_lock(&reset_list_mutex); | 353 | mutex_lock(&reset_list_mutex); |
| 326 | rcdev = NULL; | 354 | rcdev = NULL; |
| @@ -349,7 +377,7 @@ struct reset_control *__of_reset_control_get(struct device_node *node, | |||
| 349 | } | 377 | } |
| 350 | 378 | ||
| 351 | /* reset_list_mutex also protects the rcdev's reset_control list */ | 379 | /* reset_list_mutex also protects the rcdev's reset_control list */ |
| 352 | rstc = __reset_control_get(rcdev, rstc_id, shared); | 380 | rstc = __reset_control_get_internal(rcdev, rstc_id, shared); |
| 353 | 381 | ||
| 354 | mutex_unlock(&reset_list_mutex); | 382 | mutex_unlock(&reset_list_mutex); |
| 355 | 383 | ||
| @@ -357,6 +385,17 @@ struct reset_control *__of_reset_control_get(struct device_node *node, | |||
| 357 | } | 385 | } |
| 358 | EXPORT_SYMBOL_GPL(__of_reset_control_get); | 386 | EXPORT_SYMBOL_GPL(__of_reset_control_get); |
| 359 | 387 | ||
| 388 | struct reset_control *__reset_control_get(struct device *dev, const char *id, | ||
| 389 | int index, bool shared, bool optional) | ||
| 390 | { | ||
| 391 | if (dev->of_node) | ||
| 392 | return __of_reset_control_get(dev->of_node, id, index, shared, | ||
| 393 | optional); | ||
| 394 | |||
| 395 | return optional ? NULL : ERR_PTR(-EINVAL); | ||
| 396 | } | ||
| 397 | EXPORT_SYMBOL_GPL(__reset_control_get); | ||
| 398 | |||
| 360 | /** | 399 | /** |
| 361 | * reset_control_put - free the reset controller | 400 | * reset_control_put - free the reset controller |
| 362 | * @rstc: reset controller | 401 | * @rstc: reset controller |
| @@ -364,11 +403,11 @@ EXPORT_SYMBOL_GPL(__of_reset_control_get); | |||
| 364 | 403 | ||
| 365 | void reset_control_put(struct reset_control *rstc) | 404 | void reset_control_put(struct reset_control *rstc) |
| 366 | { | 405 | { |
| 367 | if (IS_ERR(rstc)) | 406 | if (IS_ERR_OR_NULL(rstc)) |
| 368 | return; | 407 | return; |
| 369 | 408 | ||
| 370 | mutex_lock(&reset_list_mutex); | 409 | mutex_lock(&reset_list_mutex); |
| 371 | __reset_control_put(rstc); | 410 | __reset_control_put_internal(rstc); |
| 372 | mutex_unlock(&reset_list_mutex); | 411 | mutex_unlock(&reset_list_mutex); |
| 373 | } | 412 | } |
| 374 | EXPORT_SYMBOL_GPL(reset_control_put); | 413 | EXPORT_SYMBOL_GPL(reset_control_put); |
| @@ -379,7 +418,8 @@ static void devm_reset_control_release(struct device *dev, void *res) | |||
| 379 | } | 418 | } |
| 380 | 419 | ||
| 381 | struct reset_control *__devm_reset_control_get(struct device *dev, | 420 | struct reset_control *__devm_reset_control_get(struct device *dev, |
| 382 | const char *id, int index, int shared) | 421 | const char *id, int index, bool shared, |
| 422 | bool optional) | ||
| 383 | { | 423 | { |
| 384 | struct reset_control **ptr, *rstc; | 424 | struct reset_control **ptr, *rstc; |
| 385 | 425 | ||
| @@ -388,8 +428,7 @@ struct reset_control *__devm_reset_control_get(struct device *dev, | |||
| 388 | if (!ptr) | 428 | if (!ptr) |
| 389 | return ERR_PTR(-ENOMEM); | 429 | return ERR_PTR(-ENOMEM); |
| 390 | 430 | ||
| 391 | rstc = __of_reset_control_get(dev ? dev->of_node : NULL, | 431 | rstc = __reset_control_get(dev, id, index, shared, optional); |
| 392 | id, index, shared); | ||
| 393 | if (!IS_ERR(rstc)) { | 432 | if (!IS_ERR(rstc)) { |
| 394 | *ptr = rstc; | 433 | *ptr = rstc; |
| 395 | devres_add(dev, ptr); | 434 | devres_add(dev, ptr); |
