From: Feng Kan <fkan@apm.com>
To: Alexandre Courbot <gnurou@gmail.com>
Cc: "devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Linus Walleij <linus.walleij@linaro.org>,
patches <patches@apm.com>, Will Deacon <will.deacon@arm.com>,
"linux-gpio@vger.kernel.org" <linux-gpio@vger.kernel.org>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH 1/3] gpio: Add APM X-Gene SoC GPIO controller support
Date: Tue, 20 May 2014 16:54:29 -0700 [thread overview]
Message-ID: <CAL85gmDjVszNd3TB51BGa+78wEEZmJfBOLNKOpTEvMTGU2VdBA@mail.gmail.com> (raw)
In-Reply-To: <CAAVeFu+TOfjfvisinv3oJ9PobdV9HcNJhr+3VYneSJ54uGwiAg@mail.gmail.com>
> +static void xgene_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
> +{
> + struct xgene_gpio_bank *bank =
> + container_of(gc, struct xgene_gpio_bank, chip);
> + unsigned long flags;
> + u32 data;
> +
> + spin_lock_irqsave(&bank->lock, flags);
> +
> + data = ioread32(bank->set_dr);
> + data = val ? data | GPIO_SET_MASK(gpio) : data & ~GPIO_SET_MASK(gpio);
>Couldn't you use set_bit() / clear_bit() instead here?
Set_bit/clear_bit seems a bit heavy, I can use the non atomic methods
of _set_bit/clear_bit
if you agree? In which case I will rewrite all the other method in
likewise fashion.
>> + bank = &gpio->banks[offs];
>> + bank->gpio = gpio;
>> + spin_lock_init(&bank->lock);
>> +
>> + if (of_property_read_u32(bank_np, "ngpios", &ngpio))
>> + ngpio = 16;
>
> Here I think you want to distinguish between "property not defined"
> (-EINVAL) and "property has no value" (-ENODATA) and other possible
> errors. In the later cases you will want to signal the error and
> return from here.
I kinda messed up here a bit, I am trying to support ACPI booting but other
properties are also affected. I will rewrite this part so minimum of_ access
methods are required.
>
>> +
>> + if ((ngpio > 16) || (ngpio < 1)) {
>> + dev_info(gpio->dev, "Incorrect number of gpio specified: %s\n",
>> + bank_np->full_name);
>> + return -EINVAL;
>> + }
>> +
>> + bank->data = gpio->regs + GPIO_DATA + (bank_idx * GPIO_DATA_OFFSET);
>> + bank->od = gpio->regs + GPIO_OD + (bank_idx * GPIO_OD_OFFSET);
>> + bank->mux = gpio->regs + GPIO_MUX + (bank_idx * GPIO_MUX_OFFSET);
>> + bank->set_dr = gpio->regs + GPIO_SET_DR
>> + + (bank_idx * GPIO_SET_DR_OFFSET);
>> +
>> + bank->chip.direction_input = xgene_gpio_dir_in;
>> + bank->chip.direction_output = xgene_gpio_dir_out;
>> + bank->chip.get = xgene_gpio_get;
>> + bank->chip.set = xgene_gpio_set;
>> +
>> + if (!of_property_read_u32(bank_np, "odcfg", &odcfg))
>> + iowrite32(odcfg, bank->od);
>> +
>> + bank->chip.ngpio = ngpio;
>> + bank->chip.of_node = bank_np;
>> + bank->chip.base = bank_idx * ngpio;
>> +
>> + err = gpiochip_add(&bank->chip);
>> + if (err)
>> + dev_err(gpio->dev, "failed to register gpiochip for %s\n",
>> + bank_np->full_name);
>> +
>> + return err;
>> +}
>> +
>> +static int xgene_gpio_probe(struct platform_device *pdev)
>> +{
>> + struct device_node *np = pdev->dev.of_node;
>> + struct resource *res;
>> + struct xgene_gpio *gpio;
>> + int err;
>> + unsigned int offs = 0;
>> +
>> + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
>> + if (!gpio)
>> + return -ENOMEM;
>> + gpio->dev = &pdev->dev;
>> +
>> + gpio->nr_banks = of_get_child_count(pdev->dev.of_node);
>> + if (!gpio->nr_banks) {
>> + err = -EINVAL;
>> + goto err;
>> + }
>
> Might be worth checking whether nr_banks >= XGENE_GPIO_MAX_PORTS and
> return an error here.
>
>> +
>> + gpio->banks = devm_kzalloc(&pdev->dev, gpio->nr_banks *
>> + sizeof(*gpio->banks), GFP_KERNEL);
>> + if (!gpio->banks) {
>> + err = -ENOMEM;
>> + goto err;
>> + }
>
> I'm fine with printing the error status the way you do, but could you
> also do the same for the first kzalloc too?
>
> Or maybe you could put your banks member at the end of the xgene_gpio
> struct as a flexible array member and perform only one kzalloc of size
> (sizeof(*gpio) + (sizeof(*gpio->banks) * gpio->nr_banks))?
>
>> +
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + gpio->regs = devm_ioremap_resource(&pdev->dev, res);
>> + if (IS_ERR(gpio->regs)) {
>> + err = PTR_ERR(gpio->regs);
>> + goto err;
>> + }
>> +
>> + for_each_child_of_node(pdev->dev.of_node, np) {
>> + err = xgene_gpio_add_bank(gpio, np, offs++);
>> + if (err)
>> + goto err;
>> + }
>> +
>> + platform_set_drvdata(pdev, gpio);
>> +
>> + dev_info(&pdev->dev, "X-Gene GPIO driver registered\n");
>> + return 0;
>> +err:
>> + dev_err(&pdev->dev, "X-Gene GPIO driver registration failed\n");
>> + return err;
>> +}
>> +
>> +static const struct of_device_id xgene_gpio_of_match[] = {
>> + { .compatible = "apm,xgene-gpio", },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(of, xgene_gpio_of_match);
>> +
>> +static struct platform_driver xgene_gpio_driver = {
>> + .driver = {
>> + .name = "xgene-gpio",
>> + .owner = THIS_MODULE,
>> + .of_match_table = xgene_gpio_of_match,
>> + },
>> + .probe = xgene_gpio_probe,
>> +};
>> +
>> +static int __init xgene_gpio_init(void)
>> +{
>> + return platform_driver_register(&xgene_gpio_driver);
>> +}
>> +postcore_initcall(xgene_gpio_init);
>> +
>> +MODULE_AUTHOR("AppliedMicro");
>> +MODULE_DESCRIPTION("APM X-Gene GPIO driver");
>> +MODULE_LICENSE("GPL");
>> --
>> 1.9.1
>>
>
> Globally the driver looks well-written, but I don't understand the
> need to have one gpio_chip per bank. Could you elaborate on the
> reasons for this design?
I see each bank as separate gpio chip. It is a simple way to
abstract the banks since they can operate independently. It also
provided me a way to fix the sysfs gpio base number, regardless if
a particular bank node is pulled out. This is also done in similar way
in some other gpio drivers such as the dwapb gpio driver.
>
> Alex.
next prev parent reply other threads:[~2014-05-20 23:54 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1400263432-922-1-git-send-email-fkan@apm.com>
[not found] ` <1400263432-922-2-git-send-email-fkan@apm.com>
2014-05-20 6:04 ` [PATCH 1/3] gpio: Add APM X-Gene SoC GPIO controller support Alexandre Courbot
2014-05-20 23:54 ` Feng Kan [this message]
2014-05-25 7:35 ` Alexandre Courbot
2014-05-27 8:25 ` Linus Walleij
2014-05-27 16:59 ` Feng Kan
2014-05-28 17:01 ` Feng Kan
2014-05-28 19:10 ` Rob Herring
2014-05-28 19:10 ` Linus Walleij
2014-05-27 7:59 ` Linus Walleij
[not found] ` <1400263432-922-3-git-send-email-fkan@apm.com>
2014-05-27 8:27 ` [PATCH 2/3] arm64:dts: Add APM X-Gene SoC GPIO controller DTS entries Linus Walleij
[not found] ` <1400263432-922-4-git-send-email-fkan@apm.com>
2014-05-20 6:11 ` [PATCH 3/3] Documentation: gpio: Add APM X-Gene SoC GPIO controller DTS binding Alexandre Courbot
2014-05-27 8:30 ` Linus Walleij
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAL85gmDjVszNd3TB51BGa+78wEEZmJfBOLNKOpTEvMTGU2VdBA@mail.gmail.com \
--to=fkan@apm.com \
--cc=catalin.marinas@arm.com \
--cc=devicetree@vger.kernel.org \
--cc=gnurou@gmail.com \
--cc=linus.walleij@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-gpio@vger.kernel.org \
--cc=patches@apm.com \
--cc=will.deacon@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).