On 2/9/2015 11:20 AM, Dmitry Torokhov wrote: > Hi Ray, > > On Wed, Feb 04, 2015 at 09:21:01AM -0800, Ray Jui wrote: >> +static int cygnus_gpio_pinmux_add_range(struct cygnus_gpio *chip) >> +{ >> + struct device_node *node = chip->dev->of_node; >> + struct device_node *pinmux_node; >> + struct platform_device *pinmux_pdev; >> + struct gpio_chip *gc = &chip->gc; >> + int i, ret; >> + >> + /* parse DT to find the phandle to the pinmux controller */ >> + pinmux_node = of_parse_phandle(node, "pinmux", 0); >> + if (!pinmux_node) >> + return -ENODEV; >> + >> + pinmux_pdev = of_find_device_by_node(pinmux_node); >> + if (!pinmux_pdev) { >> + dev_err(chip->dev, "failed to get pinmux device\n"); >> + return -EINVAL; >> + } >> + >> + /* now need to create the mapping between local GPIO and PINMUX pins */ >> + for (i = 0; i < ARRAY_SIZE(cygnus_gpio_pintable); i++) { >> + ret = gpiochip_add_pin_range(gc, dev_name(&pinmux_pdev->dev), >> + cygnus_gpio_pintable[i].offset, >> + cygnus_gpio_pintable[i].pin_base, >> + cygnus_gpio_pintable[i].num_pins); >> + if (ret) { >> + dev_err(chip->dev, "unable to add GPIO pin range\n"); >> + goto err_put_device; >> + } >> + } >> + >> + chip->pinmux_is_supported = true; >> + >> + /* no need for pinmux_pdev device reference anymore */ >> + put_device(&pinmux_pdev->dev); > > Sorry I did not notice it before, but of_parse_phandle() takes reference > to the returned device node, so you need to "put" it here and in error > path as well. Actually you can do: > > int ret = 0; > > pinmux_node = of_parse_phandle(node, "pinmux", 0); > if (!pinmux_node) > return -ENODEV; > > pinmux_pdev = of_find_device_by_node(pinmux_node); > /* We do not longer need pinmux node */ > of_node_put(pinmux_node); > > if (!pinmux_dev) > .... > > for (..) { > ... > if (ret) { > dev_err(...); > break; > } > } > > chip->pinmux_is_supported = (ret == 0); > put_device(..); > return ret; > } > > This way you free resources in the same path. > Thanks. I'll make the change. > ... > >> + >> +static struct platform_driver cygnus_gpio_driver = { >> + .driver = { >> + .name = "cygnus-gpio", >> + .of_match_table = cygnus_gpio_of_match, >> + .suppress_bind_attrs = true, >> + }, >> + .probe = cygnus_gpio_probe, >> +}; >> + >> +static int __init cygnus_gpio_init(void) >> +{ >> + return platform_driver_probe(&cygnus_gpio_driver, cygnus_gpio_probe); > > When I asked you to add ".suppress_bind_attrs = true" I missed the fact > that you were using platform_driver_probe() which already does this > internally. However platform_driver_probe() can't handle deferred > probing, which may or may not be OK. Is there a chance that any of the > resources needed by the driver return -EPROBE_DEFER? If not then it is > safe to continue using platform_driver_probe() and you can drop > suppress_bind_attrs assignment, otherwise it may be better to switch to > platform_driver_register(). > > Thanks. > No I do not expect any resource that this driver depends on to return -EPROBE_DEFER. The IOMUX driver that this driver depends on should be initialized before this driver. I'll drop .suppress_bind_attrs then. Thanks. Ray -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html