LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Linus Walleij <linus.walleij@linaro.org>
To: Chao Xie <chao.xie@marvell.com>
Cc: Alexandre Courbot <gnurou@gmail.com>,
	"linux-gpio@vger.kernel.org" <linux-gpio@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	xiechao_mail@163.com, Haojian Zhuang <haojian.zhuang@gmail.com>
Subject: Re: [PATCH] gpio: mmp: add GPIO driver for Marvell MMP series
Date: Tue, 3 Feb 2015 14:21:43 +0100	[thread overview]
Message-ID: <CACRpkdbUqCQZiSDbiD994ecF4h6xHShE8yfdrE2vNVNW+082zw@mail.gmail.com> (raw)
In-Reply-To: <1422412229-23640-1-git-send-email-chao.xie@marvell.com>

On Wed, Jan 28, 2015 at 3:30 AM, Chao Xie <chao.xie@marvell.com> wrote:

> From: Chao Xie <chao.xie@marvell.com>
>
> For some old PXA series, they used PXA GPIO driver.
> The IP of GPIO changes since PXA988 which is Marvell MMP
> series.
> It will use new way to control the GPIO level, direction
> and edge status.
>
> Signed-off-by: Chao Xie <chao.xie@marvell.com>

(...)

> +config GPIO_MMP
> +       bool "MMP GPIO support"
> +       depends on ARCH_MMP

All new simple drivers with IRQ should

select GPIOLIB_IRQCHIP

Since this looks like a basic MMIO driver I think
you should also use:

select GPIO_GENERIC

And set up simple getter/setter functions with a


> +       help
> +         Say yes here to support the MMP GPIO device at PXA1088/PXA1908/PXA1928.
> +         Comparing with PXA GPIO device, the IP of MMP GPIO changes a lot.
> +

(...)

> +++ b/drivers/gpio/gpio-mmp.c

> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/irq.h>

You don't need this include with GPIOLIB_IRQCHIP

> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/gpio.h>

#include <linux/gpio/driver.h>

> +#include <linux/clk.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irqchip/chained_irq.h>

get rid of these two includes in favor of using GPIOLIB_IRQCHIP

> +#include <linux/platform_data/gpio-mmp.h>

Add:
#include <linux/basic_mmio_gpio.h>

And implement generic GPIO using bgpio_init()

(...)
> +#define GPLR           0x0
> +#define GPDR           0xc
> +#define GPSR           0x18
> +#define GPCR           0x24
> +#define GRER           0x30
> +#define GFER           0x3c
> +#define GEDR           0x48
> +#define GSDR           0x54
> +#define GCDR           0x60
> +#define GSRER          0x6c
> +#define GCRER          0x78
> +#define GSFER          0x84
> +#define GCFER          0x90
> +#define GAPMASK                0x9c
> +#define GCPMASK                0xa8
> +
> +/* Bank will have 2^n GPIOes, and for mmp-gpio n = 5 */
> +#define BANK_GPIO_ORDER                5
> +#define BANK_GPIO_NUMBER       (1 << BANK_GPIO_ORDER)
> +#define BANK_GPIO_MASK         (BANK_GPIO_NUMBER - 1)
> +
> +#define mmp_gpio_to_bank_idx(gpio)     ((gpio) >> BANK_GPIO_ORDER)
> +#define mmp_gpio_to_bank_offset(gpio)  ((gpio) & BANK_GPIO_MASK)
> +#define mmp_bank_to_gpio(idx, offset)  (((idx) << BANK_GPIO_ORDER)     \
> +                                               | ((offset) & BANK_GPIO_MASK))
> +

This looks convoluted. Why not just register each bank as a separate
device instead of trying to figure out bank index like this?

> +struct mmp_gpio_bank {
> +       void __iomem *reg_bank;
> +       u32 irq_mask;
> +       u32 irq_rising_edge;
> +       u32 irq_falling_edge;
> +};
> +
> +struct mmp_gpio_chip {
> +       struct gpio_chip chip;

That should then be
struct bgpio_chip       bgc;

For generic GPIO.

> +       void __iomem *reg_base;
> +       int irq;
> +       struct irq_domain *domain;

These two will not be necessary to keep around with
GPIOLIB_IRQCHIP

> +       unsigned int ngpio;

This is part of struct gpio_chip so do not duplicate it.

> +       unsigned int nbank;
> +       struct mmp_gpio_bank *banks;

And those two I think you should get rid of by creating one
chip per bank.

> +};

So merge these two into one struct and instantiate one device for
each bank.

> +static int mmp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct mmp_gpio_chip *mmp_chip =
> +                       container_of(chip, struct mmp_gpio_chip, chip);
> +
> +       return irq_create_mapping(mmp_chip->domain, offset);
> +}

This function goes away with GPIOLIB_IRQCHIP.
Just leave it unassigned and let the core handle this translation.

> +static int mmp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct mmp_gpio_chip *mmp_chip =
> +                       container_of(chip, struct mmp_gpio_chip, chip);

Create a static inline to cast the gpio_chip to a mmp_chip like
this:

static inline struct mmp_gpio_chip *to_mmp(struct gpio_chip *gc)
{
    return container_of(chip, struct mmp_gpio_chip, chip);
}

Use that everywhere to simplify.

> +       struct mmp_gpio_bank *bank =
> +                       &mmp_chip->banks[mmp_gpio_to_bank_idx(offset)];
> +       u32 bit = (1 << mmp_gpio_to_bank_offset(offset));

And get rid of this by using one device per bank.

> +static int mmp_gpio_direction_output(struct gpio_chip *chip,
> +static int mmp_gpio_get(struct gpio_chip *chip, unsigned offset)
> +static void mmp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)

Looks like generic GPIO will do the job.

> +#ifdef CONFIG_OF_GPIO
> +static int mmp_gpio_of_xlate(struct gpio_chip *chip,
> +                            const struct of_phandle_args *gpiospec,
> +                            u32 *flags)
> +{
> +       struct mmp_gpio_chip *mmp_chip =
> +                       container_of(chip, struct mmp_gpio_chip, chip);
> +
> +       /* GPIO index start from 0. */
> +       if (gpiospec->args[0] >= mmp_chip->ngpio)
> +               return -EINVAL;
> +
> +       if (flags)
> +               *flags = gpiospec->args[1];
> +
> +       return gpiospec->args[0];
> +}
> +#endif

This also goes to the generic xlate with one device per bank.

> +static int mmp_gpio_irq_type(struct irq_data *d, unsigned int type)
> +static void mmp_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
> +static void mmp_ack_muxed_gpio(struct irq_data *d)
> +static void mmp_mask_muxed_gpio(struct irq_data *d)
> +static void mmp_unmask_muxed_gpio(struct irq_data *d)

Looks OK but make sure to convert to GPIOLIB_IRQCHIP and convert from
struct gpio_chip * passed as irq_data *d to the internal chip type
with the new to_mmp().

(...)

>From here:

> +static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
> +                             irq_hw_number_t hw)
> +{
> +       irq_set_chip_and_handler(irq, &mmp_muxed_gpio_chip,
> +                                handle_edge_irq);
> +       irq_set_chip_data(irq, d->host_data);
> +       set_irq_flags(irq, IRQ_TYPE_NONE);
> +
> +       return 0;
> +}
> +
> +static const struct irq_domain_ops mmp_gpio_irq_domain_ops = {
> +       .map    = mmp_irq_domain_map,
> +       .xlate  = irq_domain_xlate_twocell,
> +};


To here goes away with GPIOLIB_IRQCHIP (moved to core).

> +#ifdef CONFIG_OF_GPIO
> +       mmp_chip->chip.of_node = np;
> +       mmp_chip->chip.of_xlate = mmp_gpio_of_xlate;
> +       mmp_chip->chip.of_gpio_n_cells = 2;
> +#endif

Can't we just select or depend on OF_GPIO for this
driver and get rid of the #fidef:s?

> +static int __init mmp_gpio_init(void)
> +{
> +       return platform_driver_register(&mmp_gpio_driver);
> +}
> +postcore_initcall(mmp_gpio_init);

Why does this nees to be postcore? A normal module
would be nice.

Yours,
Linus Walleij

  parent reply	other threads:[~2015-02-03 13:21 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-28  2:30 Chao Xie
2015-01-28  3:44 ` Varka Bhadram
2015-02-03 13:21 ` Linus Walleij [this message]
2015-02-04  2:10   ` Chao Xie
2015-02-04  8:24     ` Linus Walleij
2015-02-10  6:24   ` Haojian Zhuang
2015-03-05  9:11     ` 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=CACRpkdbUqCQZiSDbiD994ecF4h6xHShE8yfdrE2vNVNW+082zw@mail.gmail.com \
    --to=linus.walleij@linaro.org \
    --cc=chao.xie@marvell.com \
    --cc=gnurou@gmail.com \
    --cc=haojian.zhuang@gmail.com \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=xiechao_mail@163.com \
    --subject='Re: [PATCH] gpio: mmp: add GPIO driver for Marvell MMP series' \
    /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

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).