int asoc_simple_card_parse_dai(struct device_node *node, struct device_node **dai_of_node, const char **dai_name, const char *list_name, const char *cells_name, int *is_single_link) { struct of_phandle_args args; int ret; if (!node) return 0; /* * Get node via "sound-dai = <&phandle port>" * it will be used as xxx_of_node on soc_bind_dai_link() */ ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args); if (ret) return ret; /* Get dai->name */ if (dai_name) { ret = snd_soc_of_get_dai_name(node, dai_name); if (ret < 0) return ret; } *dai_of_node = args.np; if (is_single_link) *is_single_link = !args.args_count; return 0; }
/** * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone * @dev: a valid struct device pointer of a sensor device. Must contain * a valid .of_node, for the sensor node. * @sensor_id: a sensor identifier, in case the sensor IP has more * than one sensors * @data: a private pointer (owned by the caller) that will be passed * back, when a temperature reading is needed. * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp. * * This function will search the list of thermal zones described in device * tree and look for the zone that refer to the sensor device pointed by * @dev->of_node as temperature providers. For the zone pointing to the * sensor node, the sensor will be added to the DT thermal zone device. * * The thermal zone temperature is provided by the @get_temp function * pointer. When called, it will have the private pointer @data back. * * The thermal zone temperature trend is provided by the @get_trend function * pointer. When called, it will have the private pointer @data back. * * TODO: * 01 - This function must enqueue the new sensor instead of using * it as the only source of temperature values. * * 02 - There must be a way to match the sensor with all thermal zones * that refer to it. * * Return: On success returns a valid struct thermal_zone_device, * otherwise, it returns a corresponding ERR_PTR(). Caller must * check the return value with help of IS_ERR() helper. */ struct thermal_zone_device * thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, const struct thermal_zone_of_device_ops *ops) { struct device_node *np, *child, *sensor_np; struct thermal_zone_device *tzd = ERR_PTR(-ENODEV); np = of_find_node_by_name(NULL, "thermal-zones"); if (!np) return ERR_PTR(-ENODEV); if (!dev || !dev->of_node) { of_node_put(np); return ERR_PTR(-EINVAL); } sensor_np = of_node_get(dev->of_node); for_each_child_of_node(np, child) { struct of_phandle_args sensor_specs; int ret, id; /* Check whether child is enabled or not */ if (!of_device_is_available(child)) continue; /* For now, thermal framework supports only 1 sensor per zone */ ret = of_parse_phandle_with_args(child, "thermal-sensors", "#thermal-sensor-cells", 0, &sensor_specs); if (ret) continue; if (sensor_specs.args_count >= 1) { id = sensor_specs.args[0]; WARN(sensor_specs.args_count > 1, "%s: too many cells in sensor specifier %d\n", sensor_specs.np->name, sensor_specs.args_count); } else { id = 0; } if (sensor_specs.np == sensor_np && id == sensor_id) { tzd = thermal_zone_of_add_sensor(child, sensor_np, data, ops); if (!IS_ERR(tzd)) tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED); of_node_put(sensor_specs.np); of_node_put(child); goto exit; } of_node_put(sensor_specs.np); } exit: of_node_put(sensor_np); of_node_put(np); return tzd; }
static int gdsc_attach(struct generic_pm_domain *domain, struct device *dev) { int ret, i = 0, j = 0; struct gdsc *sc = domain_to_gdsc(domain); struct of_phandle_args clkspec; struct device_node *np = dev->of_node; if (!sc->clock_count) return 0; ret = pm_clk_create(dev); if (ret) { dev_dbg(dev, "pm_clk_create failed %d\n", ret); return ret; } sc->clks = devm_kcalloc(dev, sc->clock_count, sizeof(sc->clks), GFP_KERNEL); if (!sc->clks) return -ENOMEM; while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec)) { if (match(clkspec.args[0], sc->clocks, sc->clock_count)) { sc->clks[j] = of_clk_get_from_provider(&clkspec); pm_clk_add_clk(dev, sc->clks[j]); j++; } else if (clkspec.args[0] == sc->root_clock) sc->root_clk = of_clk_get_from_provider(&clkspec); i++; } return 0; };
/** * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * * Returns GPIO number to use with GPIO API, or one of the errno value on the * error condition. If @flags is not NULL the function also fills in flags for * the GPIO. */ int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { struct of_phandle_args out_args; struct device_d *dev; int ret; ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, &out_args); if (ret) { pr_debug("%s: cannot parse %s property: %d\n", __func__, propname, ret); return ret; } dev = of_find_device_by_node(out_args.np); if (!dev) { pr_err("%s: unable to find device of node %s: %d\n", __func__, out_args.np->full_name, ret); return ret; } ret = gpio_get_num(dev, out_args.args[0]); if (ret < 0) { pr_err("%s: unable to get gpio num of device %s: %d\n", __func__, dev_name(dev), ret); return ret; } if (flags) *flags = out_args.args[1]; return ret; }
int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) { struct device_node *np = dev->of_node; struct of_phandle_args args; int ret; usbdev->dev = dev; ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", 0, &args); if (ret) { dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", ret); memset(usbdev, 0, sizeof(*usbdev)); return ret; } usbdev->index = args.args[0]; of_node_put(args.np); if (of_find_property(np, "disable-over-current", NULL)) usbdev->disable_oc = 1; if (of_find_property(np, "external-vbus-divider", NULL)) usbdev->evdo = 1; return 0; }
static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct of_phandle_args pinspec; struct pinctrl_dev *pctldev; int index = 0, ret; if (!np) return; for (;; index++) { ret = of_parse_phandle_with_args(np, "gpio-ranges", "#gpio-range-cells", index, &pinspec); if (ret) break; pctldev = of_pinctrl_get(pinspec.np); if (!pctldev) break; ret = gpiochip_add_pin_range(chip, pinctrl_dev_get_devname(pctldev), pinspec.args[0], pinspec.args[1], pinspec.args[2]); if (ret) break; } }
/** * of_irq_parse_one - Resolve an interrupt for a device * @device: the device whose interrupt is to be resolved * @index: index of the interrupt to resolve * @out_irq: structure of_irq filled by this function * * This function resolves an interrupt for a node by walking the interrupt tree, * finding which interrupt controller node it is attached to, and returning the * interrupt specifier that can be used to retrieve a Linux IRQ number. */ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) { struct device_node *p; const __be32 *intspec, *tmp, *addr; u32 intsize, intlen; int i, res = -EINVAL; pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index); /* OldWorld mac stuff is "special", handle out of line */ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) return of_irq_parse_oldworld(device, index, out_irq); /* Get the reg property (if any) */ addr = of_get_property(device, "reg", NULL); /* Get the interrupts property */ intspec = of_get_property(device, "interrupts", &intlen); if (intspec == NULL) { /* Try the new-style interrupts-extended */ res = of_parse_phandle_with_args(device, "interrupts-extended", "#interrupt-cells", index, out_irq); if (res) return -EINVAL; return of_irq_parse_raw(addr, out_irq); } intlen /= sizeof(*intspec); pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); /* Look for the interrupt parent. */ p = of_irq_find_parent(device); if (p == NULL) return -EINVAL; /* Get size of interrupt specifier */ tmp = of_get_property(p, "#interrupt-cells", NULL); if (tmp == NULL) goto out; intsize = be32_to_cpu(*tmp); pr_debug(" intsize=%d intlen=%d\n", intsize, intlen); /* Check index */ if ((index + 1) * intsize > intlen) goto out; /* Copy intspec into irq structure */ intspec += index * intsize; out_irq->np = p; out_irq->args_count = intsize; for (i = 0; i < intsize; i++) out_irq->args[i] = be32_to_cpup(intspec++); /* Check if there are any interrupt-map translations to process */ res = of_irq_parse_raw(addr, out_irq); out: of_node_put(p); return res; }
static int __init ar79_cpu_intc_of_init( struct device_node *node, struct device_node *parent) { int err, i, count; /* Fill the irq_wb_chan table */ count = of_count_phandle_with_args( node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells"); for (i = 0; i < count; i++) { struct of_phandle_args args; u32 irq = i; of_property_read_u32_index( node, "qca,ddr-wb-channel-interrupts", i, &irq); if (irq >= ARRAY_SIZE(irq_wb_chan)) continue; err = of_parse_phandle_with_args( node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells", i, &args); if (err) return err; irq_wb_chan[irq] = args.args[0]; pr_info("IRQ: Set flush channel of IRQ%d to %d\n", irq, args.args[0]); } return mips_cpu_irq_of_init(node, parent); }
static int asoc_simple_card_sub_parse_of(struct device_node *np, struct asoc_simple_dai *dai, struct device_node **p_node, const char **name, int *args_count) { struct of_phandle_args args; struct clk *clk; u32 val; int ret; /* * Get node via "sound-dai = <&phandle port>" * it will be used as xxx_of_node on soc_bind_dai_link() */ ret = of_parse_phandle_with_args(np, "sound-dai", "#sound-dai-cells", 0, &args); if (ret) return ret; *p_node = args.np; if (args_count) *args_count = args.args_count; /* Get dai->name */ ret = snd_soc_of_get_dai_name(np, name); if (ret < 0) return ret; /* Parse TDM slot */ ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); if (ret) return ret; /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) * or "system-clock-frequency = <xxx>" * or device's module clock. */ if (of_property_read_bool(np, "clocks")) { clk = of_clk_get(np, 0); if (IS_ERR(clk)) { ret = PTR_ERR(clk); return ret; } dai->sysclk = clk_get_rate(clk); } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { dai->sysclk = val; } else { clk = of_clk_get(args.np, 0); if (!IS_ERR(clk)) dai->sysclk = clk_get_rate(clk); } return 0; }
int axidma_of_parse_dma_nodes(struct platform_device *pdev, struct axidma_device *dev) { int i, rc; int channel; struct of_phandle_args phandle_args; struct device_node *driver_node, *dma_node; // Get the device tree node for the driver driver_node = pdev->dev.of_node; // Initialize the channel type counts dev->num_dma_tx_chans = 0; dev->num_dma_rx_chans = 0; dev->num_vdma_tx_chans = 0; dev->num_vdma_rx_chans = 0; /* For each DMA channel specified in the deivce tree, parse out the * information about the channel, namely its direction and type. */ for (i = 0; i < dev->num_chans; i++) { // Get the phanlde to the DMA channel rc = of_parse_phandle_with_args(driver_node, "dmas", "#dma-cells", i, &phandle_args); if (rc < 0) { axidma_node_err(driver_node, "Unable to get phandle %d from the " "'dmas' property.\n", i); return rc; } // Check that the phandle has the expected arguments dma_node = phandle_args.np; channel = phandle_args.args[0]; if (phandle_args.args_count < 1) { axidma_node_err(driver_node, "Phandle %d in the 'dmas' property is " "is missing the channel direciton argument.\n", i); return -EINVAL; } else if (channel != 0 && channel != 1) { axidma_node_err(driver_node, "Phandle %d in the 'dmas' property " "has an invalid channel (argument 0).\n", i); return -EINVAL; } // Parse out the information about the channel rc = axidma_of_parse_channel(dma_node, channel, &dev->channels[i], dev); if (rc < 0) { return rc; } // Parse the name of the channel rc = axidma_of_parse_dma_name(driver_node, i, &dev->channels[i]); if (rc < 0) { return rc; } } // Check that all channels have unique channel ID's return axidma_check_unique_ids(dev); }
/** * of_irq_parse_one - Resolve an interrupt for a device * @device: the device whose interrupt is to be resolved * @index: index of the interrupt to resolve * @out_irq: structure of_irq filled by this function * * This function resolves an interrupt for a node by walking the interrupt tree, * finding which interrupt controller node it is attached to, and returning the * interrupt specifier that can be used to retrieve a Linux IRQ number. */ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) { struct device_node *p; const __be32 *addr; u32 intsize; int i, res; pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index); /* OldWorld mac stuff is "special", handle out of line */ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) return of_irq_parse_oldworld(device, index, out_irq); /* Get the reg property (if any) */ addr = of_get_property(device, "reg", NULL); /* Try the new-style interrupts-extended first */ res = of_parse_phandle_with_args(device, "interrupts-extended", "#interrupt-cells", index, out_irq); if (!res) return of_irq_parse_raw(addr, out_irq); /* Look for the interrupt parent. */ p = of_irq_find_parent(device); if (p == NULL) return -EINVAL; /* Get size of interrupt specifier */ if (of_property_read_u32(p, "#interrupt-cells", &intsize)) { res = -EINVAL; goto out; } pr_debug(" parent=%pOF, intsize=%d\n", p, intsize); /* Copy intspec into irq structure */ out_irq->np = p; out_irq->args_count = intsize; for (i = 0; i < intsize; i++) { res = of_property_read_u32_index(device, "interrupts", (index * intsize) + i, out_irq->args + i); if (res) goto out; } pr_debug(" intspec=%d\n", *out_irq->args); /* Check if there are any interrupt-map translations to process */ res = of_irq_parse_raw(addr, out_irq); out: of_node_put(p); return res; }
/** * thermal_of_populate_bind_params - parse and fill cooling map data * @np: DT node containing a cooling-map node * @__tbp: data structure to be filled with cooling map info * @trips: array of thermal zone trip points * @ntrips: number of trip points inside trips. * * This function parses a cooling-map type of node represented by * @np parameter and fills the read data into @__tbp data structure. * It needs the already parsed array of trip points of the thermal zone * in consideration. * * Return: 0 on success, proper error code otherwise */ static int thermal_of_populate_bind_params(struct device_node *np, struct __thermal_bind_params *__tbp, struct thermal_trip *trips, int ntrips) { struct of_phandle_args cooling_spec; struct device_node *trip; int ret, i; u32 prop; /* Default weight. Usage is optional */ __tbp->usage = THERMAL_WEIGHT_DEFAULT; ret = of_property_read_u32(np, "contribution", &prop); if (ret == 0) __tbp->usage = prop; trip = of_parse_phandle(np, "trip", 0); if (!trip) { pr_err("missing trip property\n"); return -ENODEV; } /* match using device_node */ for (i = 0; i < ntrips; i++) if (trip == trips[i].np) { __tbp->trip_id = i; break; } if (i == ntrips) { ret = -ENODEV; goto end; } ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", 0, &cooling_spec); if (ret < 0) { pr_err("missing cooling_device property\n"); goto end; } __tbp->cooling_device = cooling_spec.np; if (cooling_spec.args_count >= 2) { /* at least min and max */ __tbp->min = cooling_spec.args[0]; __tbp->max = cooling_spec.args[1]; } else { pr_err("wrong reference to cooling device, missing limits\n"); } end: of_node_put(trip); return ret; }
/** * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone * @dev: a valid struct device pointer of a sensor device. Must contain * a valid .of_node, for the sensor node. * @sensor_id: a sensor identifier, in case the sensor IP has more * than one sensors * @data: a private pointer (owned by the caller) that will be passed * back, when a temperature reading is needed. * @get_temp: a pointer to a function that reads the sensor temperature. * @get_trend: a pointer to a function that reads the sensor temperature trend. * * This function will search the list of thermal zones described in device * tree and look for the zone that refer to the sensor device pointed by * @dev->of_node as temperature providers. For the zone pointing to the * sensor node, the sensor will be added to the DT thermal zone device. * * The thermal zone temperature is provided by the @get_temp function * pointer. When called, it will have the private pointer @data back. * * The thermal zone temperature trend is provided by the @get_trend function * pointer. When called, it will have the private pointer @data back. * * TODO: * 01 - This function must enqueue the new sensor instead of using * it as the only source of temperature values. * * 02 - There must be a way to match the sensor with all thermal zones * that refer to it. * * Return: On success returns a valid struct thermal_zone_device, * otherwise, it returns a corresponding ERR_PTR(). Caller must * check the return value with help of IS_ERR() helper. */ struct thermal_zone_device * thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, int (*get_temp)(void *, long *), int (*get_trend)(void *, long *)) { struct device_node *np, *child, *sensor_np; np = of_find_node_by_name(NULL, "thermal-zones"); if (!np) return ERR_PTR(-ENODEV); if (!dev || !dev->of_node) return ERR_PTR(-EINVAL); sensor_np = dev->of_node; for_each_child_of_node(np, child) { struct of_phandle_args sensor_specs; int ret, id; /* Check whether child is enabled or not */ if (!of_device_is_available(child)) continue; /* For now, thermal framework supports only 1 sensor per zone */ ret = of_parse_phandle_with_args(child, "thermal-sensors", "#thermal-sensor-cells", 0, &sensor_specs); if (ret) continue; if (sensor_specs.args_count >= 1) { id = sensor_specs.args[0]; WARN(sensor_specs.args_count > 1, "%s: too many cells in sensor specifier %d\n", sensor_specs.np->name, sensor_specs.args_count); } else { id = 0; } if (sensor_specs.np == sensor_np && id == sensor_id) { of_node_put(np); return thermal_zone_of_add_sensor(child, sensor_np, data, get_temp, get_trend); } } of_node_put(np); return ERR_PTR(-ENODEV); }
int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev) { struct cpg_mssr_clk_domain *pd = cpg_mssr_clk_domain; struct device_node *np = dev->of_node; struct of_phandle_args clkspec; struct clk *clk; int i = 0; int error; if (!pd) { dev_dbg(dev, "CPG/MSSR clock domain not yet available\n"); return -EPROBE_DEFER; } while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec)) { if (cpg_mssr_is_pm_clk(&clkspec, pd)) goto found; of_node_put(clkspec.np); i++; } return 0; found: clk = of_clk_get_from_provider(&clkspec); of_node_put(clkspec.np); if (IS_ERR(clk)) return PTR_ERR(clk); error = pm_clk_create(dev); if (error) { dev_err(dev, "pm_clk_create failed %d\n", error); goto fail_put; } error = pm_clk_add_clk(dev, clk); if (error) { dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error); goto fail_destroy; } return 0; fail_destroy: pm_clk_destroy(dev); fail_put: clk_put(clk); return error; }
static int clk_notify(struct notifier_block *nb, unsigned long action, void *data) { int sz, i = 0; struct device *dev = data; struct gdsc_notifier_block *gdsc_nb; struct of_phandle_args clkspec; struct device_node *np = dev->of_node; if (!of_find_property(dev->of_node, "power-domains", &sz)) return 0; gdsc_nb = container_of(nb, struct gdsc_notifier_block, nb); if (!gdsc_nb->clock_count) return 0; switch (action) { case BUS_NOTIFY_BIND_DRIVER: while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec)) { if (match(clkspec.args[0], gdsc_nb->clocks, gdsc_nb->clock_count)) enable_clock(&clkspec); i++; } break; case BUS_NOTIFY_UNBOUND_DRIVER: while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec)) { if (match(clkspec.args[0], gdsc_nb->clocks, gdsc_nb->clock_count)) disable_clock(&clkspec); i++; } break; } return 0; }
int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev) { struct device_node *np = dev->of_node; struct of_phandle_args clkspec; struct clk *clk; int i = 0; int error; while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec)) { if (of_device_is_compatible(clkspec.np, "renesas,cpg-mstp-clocks")) goto found; /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */ if (of_node_name_eq(clkspec.np, "zb_clk")) goto found; of_node_put(clkspec.np); i++; } return 0; found: clk = of_clk_get_from_provider(&clkspec); of_node_put(clkspec.np); if (IS_ERR(clk)) return PTR_ERR(clk); error = pm_clk_create(dev); if (error) { dev_err(dev, "pm_clk_create failed %d\n", error); goto fail_put; } error = pm_clk_add_clk(dev, clk); if (error) { dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error); goto fail_destroy; } return 0; fail_destroy: pm_clk_destroy(dev); fail_put: clk_put(clk); return error; }
static int imx_chipidea_probe_dt(struct imx_chipidea *ci) { struct of_phandle_args out_args; enum usb_dr_mode mode; if (of_parse_phandle_with_args(ci->dev->device_node, "fsl,usbmisc", "#index-cells", 0, &out_args)) return -ENODEV; ci->portno = out_args.args[0]; ci->flags = MXC_EHCI_MODE_UTMI_8BIT; mode = of_usb_get_dr_mode(ci->dev->device_node, NULL); switch (mode) { case USB_DR_MODE_HOST: default: ci->mode = IMX_USB_MODE_HOST; break; case USB_DR_MODE_PERIPHERAL: ci->mode = IMX_USB_MODE_DEVICE; break; } ci->phymode = of_usb_get_phy_mode(ci->dev->device_node, NULL); switch (ci->phymode) { case USBPHY_INTERFACE_MODE_UTMI: ci->flags = MXC_EHCI_MODE_UTMI_8BIT; break; case USBPHY_INTERFACE_MODE_UTMIW: ci->flags = MXC_EHCI_MODE_UTMI_16_BIT; break; case USBPHY_INTERFACE_MODE_ULPI: ci->flags = MXC_EHCI_MODE_ULPI; break; case USBPHY_INTERFACE_MODE_SERIAL: ci->flags = MXC_EHCI_MODE_SERIAL; break; case USBPHY_INTERFACE_MODE_HSIC: ci->flags = MXC_EHCI_MODE_HSIC; break; default: dev_dbg(ci->dev, "no phy_type setting. Relying on reset default\n"); } if (of_find_property(ci->dev->device_node, "disable-over-current", NULL)) ci->flags |= MXC_EHCI_DISABLE_OVERCURRENT; return 0; }
static int analog_drm_load(struct drm_device *dev, unsigned long flags) { struct analog_drm_private *private; struct of_phandle_args dma_spec; struct device_node *of_node; int ret; ret = of_parse_phandle_with_args(analog_drm_pdev->dev.of_node, "dma-request", "#dma-cells", 0, &dma_spec); if (ret) { return ret; } private = kzalloc(sizeof(struct analog_drm_private), GFP_KERNEL);
/** * of_gpio_count - Count GPIOs for a device * @np: device node to count GPIOs for * * The function returns the count of GPIOs specified for a node. * * Note that the empty GPIO specifiers counts too. For example, * * gpios = <0 * &pio1 1 2 * 0 * &pio2 3 4>; * * defines four GPIOs (so this function will return 4), two of which * are not specified. */ unsigned int of_gpio_count(struct device_node *np) { unsigned int cnt = 0; do { int ret; ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells", cnt, NULL); /* A hole in the gpios = <> counts anyway. */ if (ret < 0 && ret != -EEXIST) break; } while (++cnt); return cnt; }
struct tegra_mipi_device *tegra_mipi_request(struct device *device) { struct device_node *np = device->of_node; struct tegra_mipi_device *dev; struct of_phandle_args args; int err; err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate", "#nvidia,mipi-calibrate-cells", 0, &args); if (err < 0) return ERR_PTR(err); dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { err = -ENOMEM; goto out; } dev->pdev = of_find_device_by_node(args.np); if (!dev->pdev) { err = -ENODEV; goto free; } dev->mipi = platform_get_drvdata(dev->pdev); if (!dev->mipi) { err = -EPROBE_DEFER; goto put; } of_node_put(args.np); dev->pads = args.args[0]; dev->device = device; return dev; put: platform_device_put(dev->pdev); free: kfree(dev); out: of_node_put(args.np); return ERR_PTR(err); }
/** * of_dma_match_channel - Check if a DMA specifier matches name * @np: device node to look for DMA channels * @name: channel name to be matched * @index: index of DMA specifier in list of DMA specifiers * @dma_spec: pointer to DMA specifier as found in the device tree * * Check if the DMA specifier pointed to by the index in a list of DMA * specifiers, matches the name provided. Returns 0 if the name matches and * a valid pointer to the DMA specifier is found. Otherwise returns -ENODEV. */ static int of_dma_match_channel(struct device_node *np, const char *name, int index, struct of_phandle_args *dma_spec) { const char *s; if (of_property_read_string_index(np, "dma-names", index, &s)) return -ENODEV; if (strcmp(name, s)) return -ENODEV; if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index, dma_spec)) return -ENODEV; return 0; }
char *of_clk_get_parent_name(struct device_node *np, unsigned int index) { struct of_phandle_args clkspec; const char *clk_name; int rc; rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index, &clkspec); if (rc) return NULL; if (of_property_read_string_index(clkspec.np, "clock-output-names", clkspec.args_count ? clkspec.args[0] : 0, &clk_name) < 0) clk_name = clkspec.np->name; return xstrdup(clk_name); }
/** * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * * Returns GPIO number to use with Linux generic GPIO API, or one of the errno * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { int ret; struct gpio_chip *gc; struct of_phandle_args gpiospec; ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, &gpiospec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); goto err0; } gc = of_node_to_gpiochip(gpiospec.np); if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", np->full_name, gpiospec.np->full_name); ret = -ENODEV; goto err1; } if (gpiospec.args_count != gc->of_gpio_n_cells) { pr_debug("%s: wrong #gpio-cells for %s\n", np->full_name, gpiospec.np->full_name); ret = -EINVAL; goto err1; } /* .xlate might decide to not fill in the flags, so clear it. */ if (flags) *flags = 0; ret = gc->of_xlate(gc, &gpiospec, flags); if (ret < 0) goto err1; ret += gc->base; err1: of_node_put(gpiospec.np); err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; }
static int of_get_dml_pipe_index(struct device_node *np, const char *name) { int index; struct of_phandle_args dma_spec; index = of_property_match_string(np, "dma-names", name); if (index < 0) return -ENODEV; if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index, &dma_spec)) return -ENODEV; if (dma_spec.args_count) return dma_spec.args[0]; return -ENODEV; }
static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct of_phandle_args pinspec; struct pinctrl_dev *pctldev; int index = 0, ret; if (!np) return; do { ret = of_parse_phandle_with_args(np, "gpio-ranges", "#gpio-range-cells", index, &pinspec); if (ret) break; pctldev = of_pinctrl_get(pinspec.np); if (!pctldev) break; /* * This assumes that the n GPIO pins are consecutive in the * GPIO number space, and that the pins are also consecutive * in their local number space. Currently it is not possible * to add different ranges for one and the same GPIO chip, * as the code assumes that we have one consecutive range * on both, mapping 1-to-1. * * TODO: make the OF bindings handle multiple sparse ranges * on the same GPIO chip. */ ret = gpiochip_add_pin_range(chip, pinctrl_dev_get_name(pctldev), 0, /* offset in gpiochip */ pinspec.args[0], pinspec.args[1]); if (ret) break; } while (index++); }
static int highbank_initialize_phys(struct device *dev, void __iomem *addr) { struct device_node *sata_node = dev->of_node; int phy_count = 0, phy, port = 0, i; void __iomem *cphy_base[CPHY_PHY_COUNT] = {}; struct device_node *phy_nodes[CPHY_PHY_COUNT] = {}; u32 tx_atten[CPHY_PORT_COUNT] = {}; memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT); do { u32 tmp; struct of_phandle_args phy_data; if (of_parse_phandle_with_args(sata_node, "calxeda,port-phys", "#phy-cells", port, &phy_data)) break; for (phy = 0; phy < phy_count; phy++) { if (phy_nodes[phy] == phy_data.np) break; } if (phy_nodes[phy] == NULL) { phy_nodes[phy] = phy_data.np; cphy_base[phy] = of_iomap(phy_nodes[phy], 0); if (cphy_base[phy] == NULL) { return 0; } phy_count += 1; } port_data[port].lane_mapping = phy_data.args[0]; of_property_read_u32(phy_nodes[phy], "phydev", &tmp); port_data[port].phy_devs = tmp; port_data[port].phy_base = cphy_base[phy]; of_node_put(phy_data.np); port += 1; } while (port < CPHY_PORT_COUNT); of_property_read_u32_array(sata_node, "calxeda,tx-atten", tx_atten, port); for (i = 0; i < port; i++) port_data[i].tx_atten = (u8) tx_atten[i]; return 0; }
/** * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device * which is associated with the given phy device_node * @np: Pointer to the given phy device_node * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for * phys which do not have phy-cells * * In dts a usb controller associates with phy devices. The function gets * the string from property 'dr_mode' of the controller associated with the * given phy device node, and returns the correspondig enum usb_dr_mode. */ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) { struct device_node *controller = NULL; struct of_phandle_args args; const char *dr_mode; int index; int err; do { controller = of_find_node_with_property(controller, "phys"); index = 0; do { if (arg0 == -1) { args.np = of_parse_phandle(controller, "phys", index); args.args_count = 0; } else { err = of_parse_phandle_with_args(controller, "phys", "#phy-cells", index, &args); if (err) break; } of_node_put(args.np); if (args.np == np && (args.args_count == 0 || args.args[0] == arg0)) goto finish; index++; } while (args.np); } while (controller); finish: err = of_property_read_string(controller, "dr_mode", &dr_mode); of_node_put(controller); if (err < 0) return USB_DR_MODE_UNKNOWN; return usb_get_dr_mode_from_string(dr_mode); }
static int bcm63xx_pmb_get_resources(struct device_node *dn, void __iomem **base, unsigned int *cpu, unsigned int *addr) { struct device_node *pmb_dn; struct of_phandle_args args; int ret; ret = of_property_read_u32(dn, "reg", cpu); if (ret) { pr_err("CPU is missing a reg node\n"); return ret; } ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells", 0, &args); if (ret) { pr_err("CPU is missing a resets phandle\n"); return ret; } pmb_dn = args.np; if (args.args_count != 2) { pr_err("reset-controller does not conform to reset-cells\n"); return -EINVAL; } *base = of_iomap(args.np, 0); if (!*base) { pr_err("failed remapping PMB register\n"); return -ENOMEM; } /* We do not need the number of zones */ *addr = args.args[0]; return 0; }
static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) { struct device_node *np = dev->of_node; struct of_phandle_args args; struct imx_usbmisc_data *data; int ret; /* * In case the fsl,usbmisc property is not present this device doesn't * need usbmisc. Return NULL (which is no error here) */ if (!of_get_property(np, "fsl,usbmisc", NULL)) return NULL; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return ERR_PTR(-ENOMEM); ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", 0, &args); if (ret) { dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", ret); return ERR_PTR(ret); } data->index = args.args[0]; of_node_put(args.np); if (of_find_property(np, "disable-over-current", NULL)) data->disable_oc = 1; if (of_find_property(np, "external-vbus-divider", NULL)) data->evdo = 1; return data; }
static void __init of_selftest_parse_phandle_with_args(void) { struct device_node *np; struct of_phandle_args args; int rc, i; bool passed_all = true; pr_info("start\n"); np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); if (!np) { pr_err("missing testcase data\n"); return; } for (i = 0; i < 7; i++) { bool passed = true; rc = of_parse_phandle_with_args(np, "phandle-list", "#phandle-cells", i, &args); /* Test the values from tests-phandle.dtsi */ switch (i) { case 0: passed &= !rc; passed &= (args.args_count == 1); passed &= (args.args[0] == (i + 1)); break; case 1: passed &= !rc; passed &= (args.args_count == 2); passed &= (args.args[0] == (i + 1)); passed &= (args.args[1] == 0); break; case 2: passed &= (rc == -ENOENT); break; case 3: passed &= !rc; passed &= (args.args_count == 3); passed &= (args.args[0] == (i + 1)); passed &= (args.args[1] == 4); passed &= (args.args[2] == 3); break; case 4: passed &= !rc; passed &= (args.args_count == 2); passed &= (args.args[0] == (i + 1)); passed &= (args.args[1] == 100); break; case 5: passed &= !rc; passed &= (args.args_count == 0); break; case 6: passed &= !rc; passed &= (args.args_count == 1); passed &= (args.args[0] == (i + 1)); break; case 7: passed &= (rc == -EINVAL); break; default: passed = false; } if (!passed) { int j; pr_err("index %i - data error on node %s rc=%i regs=[", i, args.np->full_name, rc); for (j = 0; j < args.args_count; j++) printk(" %i", args.args[j]); printk(" ]\n"); passed_all = false; } } /* Check for missing list property */ rc = of_parse_phandle_with_args(np, "phandle-list-missing", "#phandle-cells", 0, &args); passed_all &= (rc == -EINVAL); /* Check for missing cells property */ rc = of_parse_phandle_with_args(np, "phandle-list", "#phandle-cells-missing", 0, &args); passed_all &= (rc == -EINVAL); /* Check for bad phandle in list */ rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle", "#phandle-cells", 0, &args); passed_all &= (rc == -EINVAL); /* Check for incorrectly formed argument list */ rc = of_parse_phandle_with_args(np, "phandle-list-bad-args", "#phandle-cells", 1, &args); passed_all &= (rc == -EINVAL); pr_info("end - %s\n", passed_all ? "PASS" : "FAIL"); }