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

reset: gpio: use software nodes to setup the GPIO lookup

GPIO machine lookup is a nice mechanism for associating GPIOs with
consumers if we don't know what kind of device the GPIO provider is or
when it will become available. However in the case of the reset-gpio, we
are already holding a reference to the device and so can reference its
firmware node. Let's setup a software node that references the relevant
GPIO and attach it to the auxiliary device we're creating.

Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Bartosz Golaszewski and committed by
Philipp Zabel
5fc4e4cf 109ce747

+74 -53
+74 -53
drivers/reset/core.c
··· 14 14 #include <linux/export.h> 15 15 #include <linux/gpio/driver.h> 16 16 #include <linux/gpio/machine.h> 17 + #include <linux/gpio/property.h> 17 18 #include <linux/idr.h> 18 19 #include <linux/kernel.h> 19 20 #include <linux/kref.h> ··· 78 77 /** 79 78 * struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices 80 79 * @of_args: phandle to the reset controller with all the args like GPIO number 80 + * @swnode: Software node containing the reference to the GPIO provider 81 81 * @list: list entry for the reset_gpio_lookup_list 82 82 */ 83 83 struct reset_gpio_lookup { 84 84 struct of_phandle_args of_args; 85 + struct fwnode_handle *swnode; 85 86 struct list_head list; 86 87 }; 87 88 ··· 852 849 kref_put(&rstc->refcnt, __reset_control_release); 853 850 } 854 851 855 - static int __reset_add_reset_gpio_lookup(struct gpio_device *gdev, int id, 856 - struct device_node *np, 857 - unsigned int gpio, 858 - unsigned int of_flags) 852 + static void reset_gpio_aux_device_release(struct device *dev) 859 853 { 860 - unsigned int lookup_flags; 861 - const char *label_tmp; 854 + struct auxiliary_device *adev = to_auxiliary_dev(dev); 862 855 863 - /* 864 - * Later we map GPIO flags between OF and Linux, however not all 865 - * constants from include/dt-bindings/gpio/gpio.h and 866 - * include/linux/gpio/machine.h match each other. 867 - */ 868 - if (of_flags > GPIO_ACTIVE_LOW) { 869 - pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n", 870 - of_flags, gpio); 871 - return -EINVAL; 856 + kfree(adev); 857 + } 858 + 859 + static int reset_add_gpio_aux_device(struct device *parent, 860 + struct fwnode_handle *swnode, 861 + int id, void *pdata) 862 + { 863 + struct auxiliary_device *adev; 864 + int ret; 865 + 866 + adev = kzalloc(sizeof(*adev), GFP_KERNEL); 867 + if (!adev) 868 + return -ENOMEM; 869 + 870 + adev->id = id; 871 + adev->name = "gpio"; 872 + adev->dev.parent = parent; 873 + adev->dev.platform_data = pdata; 874 + adev->dev.release = reset_gpio_aux_device_release; 875 + device_set_node(&adev->dev, swnode); 876 + 877 + ret = auxiliary_device_init(adev); 878 + if (ret) { 879 + kfree(adev); 880 + return ret; 872 881 } 873 882 874 - label_tmp = gpio_device_get_label(gdev); 875 - if (!label_tmp) 876 - return -EINVAL; 883 + ret = __auxiliary_device_add(adev, "reset"); 884 + if (ret) { 885 + auxiliary_device_uninit(adev); 886 + kfree(adev); 887 + return ret; 888 + } 877 889 878 - char *label __free(kfree) = kstrdup(label_tmp, GFP_KERNEL); 879 - if (!label) 880 - return -ENOMEM; 881 - 882 - /* Size: one lookup entry plus sentinel */ 883 - struct gpiod_lookup_table *lookup __free(kfree) = kzalloc(struct_size(lookup, table, 2), 884 - GFP_KERNEL); 885 - if (!lookup) 886 - return -ENOMEM; 887 - 888 - lookup->dev_id = kasprintf(GFP_KERNEL, "reset.gpio.%d", id); 889 - if (!lookup->dev_id) 890 - return -ENOMEM; 891 - 892 - lookup_flags = GPIO_PERSISTENT; 893 - lookup_flags |= of_flags & GPIO_ACTIVE_LOW; 894 - lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset", 895 - lookup_flags); 896 - 897 - /* Not freed on success, because it is persisent subsystem data. */ 898 - gpiod_add_lookup_table(no_free_ptr(lookup)); 899 - 900 - return 0; 890 + return ret; 901 891 } 902 892 903 893 /* ··· 898 902 */ 899 903 static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) 900 904 { 905 + struct property_entry properties[2] = { }; 906 + unsigned int offset, of_flags, lflags; 901 907 struct reset_gpio_lookup *rgpio_dev; 902 - struct auxiliary_device *adev; 908 + struct device *parent; 903 909 int id, ret; 904 910 905 911 /* ··· 920 922 */ 921 923 lockdep_assert_not_held(&reset_list_mutex); 922 924 925 + offset = args->args[0]; 926 + of_flags = args->args[1]; 927 + 928 + /* 929 + * Later we map GPIO flags between OF and Linux, however not all 930 + * constants from include/dt-bindings/gpio/gpio.h and 931 + * include/linux/gpio/machine.h match each other. 932 + * 933 + * FIXME: Find a better way of translating OF flags to GPIO lookup 934 + * flags. 935 + */ 936 + if (of_flags > GPIO_ACTIVE_LOW) { 937 + pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n", 938 + of_flags, offset); 939 + return -EINVAL; 940 + } 941 + 923 942 struct gpio_device *gdev __free(gpio_device_put) = 924 943 gpio_device_find_by_fwnode(of_fwnode_handle(args->np)); 925 944 if (!gdev) ··· 951 936 } 952 937 } 953 938 939 + lflags = GPIO_PERSISTENT | (of_flags & GPIO_ACTIVE_LOW); 940 + parent = gpio_device_to_device(gdev); 941 + properties[0] = PROPERTY_ENTRY_GPIO("reset-gpios", parent->fwnode, offset, lflags); 942 + 954 943 id = ida_alloc(&reset_gpio_ida, GFP_KERNEL); 955 944 if (id < 0) 956 945 return id; ··· 966 947 goto err_ida_free; 967 948 } 968 949 969 - ret = __reset_add_reset_gpio_lookup(gdev, id, args->np, args->args[0], 970 - args->args[1]); 971 - if (ret < 0) 972 - goto err_kfree; 973 - 974 950 rgpio_dev->of_args = *args; 975 951 /* 976 952 * We keep the device_node reference, but of_args.np is put at the end ··· 973 959 * Hold reference as long as rgpio_dev memory is valid. 974 960 */ 975 961 of_node_get(rgpio_dev->of_args.np); 976 - adev = auxiliary_device_create(gpio_device_to_device(gdev), "reset", 977 - "gpio", &rgpio_dev->of_args, id); 978 - ret = PTR_ERR_OR_ZERO(adev); 962 + 963 + rgpio_dev->swnode = fwnode_create_software_node(properties, NULL); 964 + if (IS_ERR(rgpio_dev->swnode)) { 965 + ret = PTR_ERR(rgpio_dev->swnode); 966 + goto err_put_of_node; 967 + } 968 + 969 + ret = reset_add_gpio_aux_device(parent, rgpio_dev->swnode, id, 970 + &rgpio_dev->of_args); 979 971 if (ret) 980 - goto err_put; 972 + goto err_del_swnode; 981 973 982 974 list_add(&rgpio_dev->list, &reset_gpio_lookup_list); 983 975 984 976 return 0; 985 977 986 - err_put: 978 + err_del_swnode: 979 + fwnode_remove_software_node(rgpio_dev->swnode); 980 + err_put_of_node: 987 981 of_node_put(rgpio_dev->of_args.np); 988 - err_kfree: 989 982 kfree(rgpio_dev); 990 983 err_ida_free: 991 984 ida_free(&reset_gpio_ida, id);