/* * Version ID Register * Bits [31:24] - Major Version * Bits [23:16] - Minor Version * Bits [15:0] - Revision Number
*/ #define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */ #define GPIO_TYPE_V2 (0x01000C2B) #define GPIO_TYPE_V2_1 (0x0101157C) #define GPIO_TYPE_V2_2 (0x010219C8)
/* Only the v1 needs to configure div_en and div_con for dbclk */ if (debounce) { if (div_debounce_support) { /* Configure the max debounce from consumers */
cur_div_reg = readl(bank->reg_base +
reg->dbclk_div_con); if (cur_div_reg < div_reg)
writel(div_reg, bank->reg_base +
reg->dbclk_div_con);
rockchip_gpio_writel_bit(bank, offset, 1,
reg->dbclk_div_en);
}
/* Enable or disable dbclk at last */ if (div_debounce_support) { if (debounce)
clk_prepare_enable(bank->db_clk); else
clk_disable_unprepare(bank->db_clk);
}
/* * gpiolib set_config callback function. The setting of the pin * mux function as 'gpio output' will be handled by the pinctrl subsystem * interface.
*/ staticint rockchip_gpio_set_config(struct gpio_chip *gc, unsignedint offset, unsignedlong config)
{ enum pin_config_param param = pinconf_to_config_param(config);
switch (param) { case PIN_CONFIG_INPUT_DEBOUNCE:
rockchip_gpio_set_debounce(gc, offset, true); /* * Rockchip's gpio could only support up to one period * of the debounce clock(pclk), which is far away from * satisftying the requirement, as pclk is usually near * 100MHz shared by all peripherals. So the fact is it * has crippled debounce capability could only be useful * to prevent any spurious glitches from waking up the system * if the gpio is conguired as wakeup interrupt source. Let's * still return -ENOTSUPP as before, to make sure the caller * of gpiod_set_debounce won't change its behaviour.
*/ return -ENOTSUPP; default: return -ENOTSUPP;
}
}
/* * gpiod_to_irq() callback function. Creates a mapping between a GPIO pin * and a virtual IRQ, if not already present.
*/ staticint rockchip_gpio_to_irq(struct gpio_chip *gc, unsignedint offset)
{ struct rockchip_pin_bank *bank = gpiochip_get_data(gc); unsignedint virq;
/* * Linux assumes that all interrupts start out disabled/masked. * Our driver only uses the concept of masked and always keeps * things enabled, so for us that's all masked and all enabled.
*/
rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_mask);
rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->port_eoi);
rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_en);
gc->mask_cache = 0xffffffff;
ret = gpiochip_add_data(gc, bank); if (ret) {
dev_err(bank->dev, "failed to add gpiochip %s, %d\n",
gc->label, ret); return ret;
}
/* * For DeviceTree-supported systems, the gpio core checks the * pinctrl's device node for the "gpio-ranges" property. * If it is present, it takes care of adding the pin ranges * for the driver. In this case the driver can skip ahead. * * In order to remain compatible with older, existing DeviceTree * files which don't set the "gpio-ranges" property or systems that * utilize ACPI the driver has to call gpiochip_add_pin_range().
*/ if (!of_property_present(bank->of_node, "gpio-ranges")) { struct device_node *pctlnp = of_get_parent(bank->of_node); struct pinctrl_dev *pctldev = NULL;
if (!pctlnp) return -ENODATA;
pctldev = of_pinctrl_get(pctlnp);
of_node_put(pctlnp); if (!pctldev) return -ENODEV;
ret = gpiochip_add_pin_range(gc, dev_name(pctldev->dev), 0,
gc->base, gc->ngpio); if (ret) {
dev_err(bank->dev, "Failed to add pin range\n"); goto fail;
}
}
ret = rockchip_interrupts_register(bank); if (ret) {
dev_err(bank->dev, "failed to register interrupt, %d\n", ret); goto fail;
}
return 0;
fail:
gpiochip_remove(&bank->gpio_chip);
return ret;
}
staticint rockchip_get_bank_data(struct rockchip_pin_bank *bank)
{ struct resource res; int id = 0;
if (of_address_to_resource(bank->of_node, 0, &res)) {
dev_err(bank->dev, "cannot find IO resource for bank\n"); return -ENOENT;
}
bank->reg_base = devm_ioremap_resource(bank->dev, &res); if (IS_ERR(bank->reg_base)) return PTR_ERR(bank->reg_base);
bank->irq = irq_of_parse_and_map(bank->of_node, 0); if (!bank->irq) return -EINVAL;
bank->clk = of_clk_get(bank->of_node, 0); if (IS_ERR(bank->clk)) return PTR_ERR(bank->clk);
clk_prepare_enable(bank->clk);
id = readl(bank->reg_base + gpio_regs_v2.version_id);
switch (id) { case GPIO_TYPE_V2: case GPIO_TYPE_V2_1: case GPIO_TYPE_V2_2:
bank->gpio_regs = &gpio_regs_v2;
bank->gpio_type = GPIO_TYPE_V2;
bank->db_clk = of_clk_get(bank->of_node, 1); if (IS_ERR(bank->db_clk)) {
dev_err(bank->dev, "cannot find debounce clk\n");
clk_disable_unprepare(bank->clk); return -EINVAL;
} break; case GPIO_TYPE_V1:
bank->gpio_regs = &gpio_regs_v1;
bank->gpio_type = GPIO_TYPE_V1; break; default:
dev_err(bank->dev, "unsupported version ID: 0x%08x\n", id); return -ENODEV;
}
return 0;
}
staticstruct rockchip_pin_bank *
rockchip_gpio_find_bank(struct pinctrl_dev *pctldev, int id)
{ struct rockchip_pinctrl *info; struct rockchip_pin_bank *bank; int i, found = 0;
info = pinctrl_dev_get_drvdata(pctldev);
bank = info->ctrl->pin_banks; for (i = 0; i < info->ctrl->nr_banks; i++, bank++) { if (bank->bank_num == id) {
found = 1; break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.