xref: /openbmc/u-boot/drivers/reset/reset-uclass.c (revision e7012e6e1f9e1c16f093d71bd53b34a6467f07bc)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
289c1e2daSStephen Warren /*
389c1e2daSStephen Warren  * Copyright (c) 2016, NVIDIA CORPORATION.
489c1e2daSStephen Warren  */
589c1e2daSStephen Warren 
689c1e2daSStephen Warren #include <common.h>
789c1e2daSStephen Warren #include <dm.h>
889c1e2daSStephen Warren #include <fdtdec.h>
989c1e2daSStephen Warren #include <reset.h>
1089c1e2daSStephen Warren #include <reset-uclass.h>
1189c1e2daSStephen Warren 
reset_dev_ops(struct udevice * dev)1289c1e2daSStephen Warren static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
1389c1e2daSStephen Warren {
1489c1e2daSStephen Warren 	return (struct reset_ops *)dev->driver->ops;
1589c1e2daSStephen Warren }
1689c1e2daSStephen Warren 
reset_of_xlate_default(struct reset_ctl * reset_ctl,struct ofnode_phandle_args * args)1789c1e2daSStephen Warren static int reset_of_xlate_default(struct reset_ctl *reset_ctl,
1840a475e8SSimon Glass 				  struct ofnode_phandle_args *args)
1989c1e2daSStephen Warren {
2089c1e2daSStephen Warren 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
2189c1e2daSStephen Warren 
2289c1e2daSStephen Warren 	if (args->args_count != 1) {
2389c1e2daSStephen Warren 		debug("Invaild args_count: %d\n", args->args_count);
2489c1e2daSStephen Warren 		return -EINVAL;
2589c1e2daSStephen Warren 	}
2689c1e2daSStephen Warren 
2789c1e2daSStephen Warren 	reset_ctl->id = args->args[0];
2889c1e2daSStephen Warren 
2989c1e2daSStephen Warren 	return 0;
3089c1e2daSStephen Warren }
3189c1e2daSStephen Warren 
reset_get_by_index(struct udevice * dev,int index,struct reset_ctl * reset_ctl)3289c1e2daSStephen Warren int reset_get_by_index(struct udevice *dev, int index,
3389c1e2daSStephen Warren 		       struct reset_ctl *reset_ctl)
3489c1e2daSStephen Warren {
3540a475e8SSimon Glass 	struct ofnode_phandle_args args;
3689c1e2daSStephen Warren 	int ret;
3789c1e2daSStephen Warren 	struct udevice *dev_reset;
3889c1e2daSStephen Warren 	struct reset_ops *ops;
3989c1e2daSStephen Warren 
4089c1e2daSStephen Warren 	debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index,
4189c1e2daSStephen Warren 	      reset_ctl);
423b9d1bddSPatrice Chotard 	reset_ctl->dev = NULL;
4389c1e2daSStephen Warren 
4440a475e8SSimon Glass 	ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
4589c1e2daSStephen Warren 					  index, &args);
4689c1e2daSStephen Warren 	if (ret) {
4740a475e8SSimon Glass 		debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n",
4889c1e2daSStephen Warren 		      __func__, ret);
4989c1e2daSStephen Warren 		return ret;
5089c1e2daSStephen Warren 	}
5189c1e2daSStephen Warren 
5240a475e8SSimon Glass 	ret = uclass_get_device_by_ofnode(UCLASS_RESET, args.node,
5389c1e2daSStephen Warren 					  &dev_reset);
5489c1e2daSStephen Warren 	if (ret) {
5540a475e8SSimon Glass 		debug("%s: uclass_get_device_by_ofnode() failed: %d\n",
5689c1e2daSStephen Warren 		      __func__, ret);
5740a475e8SSimon Glass 		debug("%s %d\n", ofnode_get_name(args.node), args.args[0]);
5889c1e2daSStephen Warren 		return ret;
5989c1e2daSStephen Warren 	}
6089c1e2daSStephen Warren 	ops = reset_dev_ops(dev_reset);
6189c1e2daSStephen Warren 
6289c1e2daSStephen Warren 	reset_ctl->dev = dev_reset;
6389c1e2daSStephen Warren 	if (ops->of_xlate)
6489c1e2daSStephen Warren 		ret = ops->of_xlate(reset_ctl, &args);
6589c1e2daSStephen Warren 	else
6689c1e2daSStephen Warren 		ret = reset_of_xlate_default(reset_ctl, &args);
6789c1e2daSStephen Warren 	if (ret) {
6889c1e2daSStephen Warren 		debug("of_xlate() failed: %d\n", ret);
6989c1e2daSStephen Warren 		return ret;
7089c1e2daSStephen Warren 	}
7189c1e2daSStephen Warren 
7289c1e2daSStephen Warren 	ret = ops->request(reset_ctl);
7389c1e2daSStephen Warren 	if (ret) {
7489c1e2daSStephen Warren 		debug("ops->request() failed: %d\n", ret);
7589c1e2daSStephen Warren 		return ret;
7689c1e2daSStephen Warren 	}
7789c1e2daSStephen Warren 
7889c1e2daSStephen Warren 	return 0;
7989c1e2daSStephen Warren }
8089c1e2daSStephen Warren 
reset_get_bulk(struct udevice * dev,struct reset_ctl_bulk * bulk)810c282339SNeil Armstrong int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
820c282339SNeil Armstrong {
830c282339SNeil Armstrong 	int i, ret, err, count;
840c282339SNeil Armstrong 
850c282339SNeil Armstrong 	bulk->count = 0;
860c282339SNeil Armstrong 
870c282339SNeil Armstrong 	count = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
88895a82ceSNeil Armstrong 	if (count < 1)
89895a82ceSNeil Armstrong 		return count;
900c282339SNeil Armstrong 
910c282339SNeil Armstrong 	bulk->resets = devm_kcalloc(dev, count, sizeof(struct reset_ctl),
920c282339SNeil Armstrong 				    GFP_KERNEL);
930c282339SNeil Armstrong 	if (!bulk->resets)
940c282339SNeil Armstrong 		return -ENOMEM;
950c282339SNeil Armstrong 
960c282339SNeil Armstrong 	for (i = 0; i < count; i++) {
970c282339SNeil Armstrong 		ret = reset_get_by_index(dev, i, &bulk->resets[i]);
980c282339SNeil Armstrong 		if (ret < 0)
990c282339SNeil Armstrong 			goto bulk_get_err;
1000c282339SNeil Armstrong 
1010c282339SNeil Armstrong 		++bulk->count;
1020c282339SNeil Armstrong 	}
1030c282339SNeil Armstrong 
1040c282339SNeil Armstrong 	return 0;
1050c282339SNeil Armstrong 
1060c282339SNeil Armstrong bulk_get_err:
1070c282339SNeil Armstrong 	err = reset_release_all(bulk->resets, bulk->count);
1080c282339SNeil Armstrong 	if (err)
1090c282339SNeil Armstrong 		debug("%s: could release all resets for %p\n",
1100c282339SNeil Armstrong 		      __func__, dev);
1110c282339SNeil Armstrong 
1120c282339SNeil Armstrong 	return ret;
1130c282339SNeil Armstrong }
1140c282339SNeil Armstrong 
reset_get_by_name(struct udevice * dev,const char * name,struct reset_ctl * reset_ctl)11589c1e2daSStephen Warren int reset_get_by_name(struct udevice *dev, const char *name,
11689c1e2daSStephen Warren 		     struct reset_ctl *reset_ctl)
11789c1e2daSStephen Warren {
11889c1e2daSStephen Warren 	int index;
11989c1e2daSStephen Warren 
12089c1e2daSStephen Warren 	debug("%s(dev=%p, name=%s, reset_ctl=%p)\n", __func__, dev, name,
12189c1e2daSStephen Warren 	      reset_ctl);
1223b9d1bddSPatrice Chotard 	reset_ctl->dev = NULL;
12389c1e2daSStephen Warren 
12440a475e8SSimon Glass 	index = dev_read_stringlist_search(dev, "reset-names", name);
12589c1e2daSStephen Warren 	if (index < 0) {
126b02e4044SSimon Glass 		debug("fdt_stringlist_search() failed: %d\n", index);
12789c1e2daSStephen Warren 		return index;
12889c1e2daSStephen Warren 	}
12989c1e2daSStephen Warren 
13089c1e2daSStephen Warren 	return reset_get_by_index(dev, index, reset_ctl);
13189c1e2daSStephen Warren }
13289c1e2daSStephen Warren 
reset_request(struct reset_ctl * reset_ctl)1339bd5cdf6SPatrice Chotard int reset_request(struct reset_ctl *reset_ctl)
1349bd5cdf6SPatrice Chotard {
1359bd5cdf6SPatrice Chotard 	struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
1369bd5cdf6SPatrice Chotard 
1379bd5cdf6SPatrice Chotard 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
1389bd5cdf6SPatrice Chotard 
1399bd5cdf6SPatrice Chotard 	return ops->request(reset_ctl);
1409bd5cdf6SPatrice Chotard }
1419bd5cdf6SPatrice Chotard 
reset_free(struct reset_ctl * reset_ctl)14289c1e2daSStephen Warren int reset_free(struct reset_ctl *reset_ctl)
14389c1e2daSStephen Warren {
14489c1e2daSStephen Warren 	struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
14589c1e2daSStephen Warren 
14689c1e2daSStephen Warren 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
14789c1e2daSStephen Warren 
14889c1e2daSStephen Warren 	return ops->free(reset_ctl);
14989c1e2daSStephen Warren }
15089c1e2daSStephen Warren 
reset_assert(struct reset_ctl * reset_ctl)15189c1e2daSStephen Warren int reset_assert(struct reset_ctl *reset_ctl)
15289c1e2daSStephen Warren {
15389c1e2daSStephen Warren 	struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
15489c1e2daSStephen Warren 
15589c1e2daSStephen Warren 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
15689c1e2daSStephen Warren 
15789c1e2daSStephen Warren 	return ops->rst_assert(reset_ctl);
15889c1e2daSStephen Warren }
15989c1e2daSStephen Warren 
reset_assert_bulk(struct reset_ctl_bulk * bulk)1600c282339SNeil Armstrong int reset_assert_bulk(struct reset_ctl_bulk *bulk)
1610c282339SNeil Armstrong {
1620c282339SNeil Armstrong 	int i, ret;
1630c282339SNeil Armstrong 
1640c282339SNeil Armstrong 	for (i = 0; i < bulk->count; i++) {
1650c282339SNeil Armstrong 		ret = reset_assert(&bulk->resets[i]);
1660c282339SNeil Armstrong 		if (ret < 0)
1670c282339SNeil Armstrong 			return ret;
1680c282339SNeil Armstrong 	}
1690c282339SNeil Armstrong 
1700c282339SNeil Armstrong 	return 0;
1710c282339SNeil Armstrong }
1720c282339SNeil Armstrong 
reset_deassert(struct reset_ctl * reset_ctl)17389c1e2daSStephen Warren int reset_deassert(struct reset_ctl *reset_ctl)
17489c1e2daSStephen Warren {
17589c1e2daSStephen Warren 	struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
17689c1e2daSStephen Warren 
17789c1e2daSStephen Warren 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
17889c1e2daSStephen Warren 
17989c1e2daSStephen Warren 	return ops->rst_deassert(reset_ctl);
18089c1e2daSStephen Warren }
18189c1e2daSStephen Warren 
reset_deassert_bulk(struct reset_ctl_bulk * bulk)1820c282339SNeil Armstrong int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
1830c282339SNeil Armstrong {
1840c282339SNeil Armstrong 	int i, ret;
1850c282339SNeil Armstrong 
1860c282339SNeil Armstrong 	for (i = 0; i < bulk->count; i++) {
1870c282339SNeil Armstrong 		ret = reset_deassert(&bulk->resets[i]);
1880c282339SNeil Armstrong 		if (ret < 0)
1890c282339SNeil Armstrong 			return ret;
1900c282339SNeil Armstrong 	}
1910c282339SNeil Armstrong 
1920c282339SNeil Armstrong 	return 0;
1930c282339SNeil Armstrong }
1940c282339SNeil Armstrong 
reset_status(struct reset_ctl * reset_ctl)195*e7012e6eSAndreas Dannenberg int reset_status(struct reset_ctl *reset_ctl)
196*e7012e6eSAndreas Dannenberg {
197*e7012e6eSAndreas Dannenberg 	struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
198*e7012e6eSAndreas Dannenberg 
199*e7012e6eSAndreas Dannenberg 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
200*e7012e6eSAndreas Dannenberg 
201*e7012e6eSAndreas Dannenberg 	return ops->rst_status(reset_ctl);
202*e7012e6eSAndreas Dannenberg }
203*e7012e6eSAndreas Dannenberg 
reset_release_all(struct reset_ctl * reset_ctl,int count)2043b9d1bddSPatrice Chotard int reset_release_all(struct reset_ctl *reset_ctl, int count)
2053b9d1bddSPatrice Chotard {
2063b9d1bddSPatrice Chotard 	int i, ret;
2073b9d1bddSPatrice Chotard 
2083b9d1bddSPatrice Chotard 	for (i = 0; i < count; i++) {
2093b9d1bddSPatrice Chotard 		debug("%s(reset_ctl[%d]=%p)\n", __func__, i, &reset_ctl[i]);
2103b9d1bddSPatrice Chotard 
2113b9d1bddSPatrice Chotard 		/* check if reset has been previously requested */
2123b9d1bddSPatrice Chotard 		if (!reset_ctl[i].dev)
2133b9d1bddSPatrice Chotard 			continue;
2143b9d1bddSPatrice Chotard 
2153b9d1bddSPatrice Chotard 		ret = reset_assert(&reset_ctl[i]);
2163b9d1bddSPatrice Chotard 		if (ret)
2173b9d1bddSPatrice Chotard 			return ret;
2183b9d1bddSPatrice Chotard 
2193b9d1bddSPatrice Chotard 		ret = reset_free(&reset_ctl[i]);
2203b9d1bddSPatrice Chotard 		if (ret)
2213b9d1bddSPatrice Chotard 			return ret;
2223b9d1bddSPatrice Chotard 	}
2233b9d1bddSPatrice Chotard 
2243b9d1bddSPatrice Chotard 	return 0;
2253b9d1bddSPatrice Chotard }
2263b9d1bddSPatrice Chotard 
22789c1e2daSStephen Warren UCLASS_DRIVER(reset) = {
22889c1e2daSStephen Warren 	.id		= UCLASS_RESET,
22989c1e2daSStephen Warren 	.name		= "reset",
23089c1e2daSStephen Warren };
231