diff mbox

gpio: sn54hc595: new driver for GPIO shift registers chipsets

Message ID 1418048833-27658-1-git-send-email-zajec5@gmail.com
State New, archived
Headers show

Commit Message

Rafał Miłecki Dec. 8, 2014, 2:27 p.m. UTC
SN54HC595 and SN74HC595 are devices based on shift registers controlled
with 5 input signals (serial-in) and providing 8 outputs (parallel-out).

They are present on some Broadcom home router boards where manufacturer
needed few extra GPIOs.

This driver simply uses specified GPIOs to control shift registers and
registers another GPIO chip. So you can call it a GPIO extender.

Due to the hardware design only output direction is supported. Reading
values is handled using tiny internal cache.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
 .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
 drivers/gpio/Kconfig                               |  11 ++
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
 4 files changed, 266 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-sn54hc595.txt
 create mode 100644 drivers/gpio/gpio-sn54hc595.c

Comments

Geert Uytterhoeven Dec. 8, 2014, 2:41 p.m. UTC | #1
Hi Rafał,

On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
> SN54HC595 and SN74HC595 are devices based on shift registers controlled
> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
>
> They are present on some Broadcom home router boards where manufacturer
> needed few extra GPIOs.
>
> This driver simply uses specified GPIOs to control shift registers and
> registers another GPIO chip. So you can call it a GPIO extender.
>
> Due to the hardware design only output direction is supported. Reading
> values is handled using tiny internal cache.
>
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> ---
>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
>  drivers/gpio/Kconfig                               |  11 ++
>  drivers/gpio/Makefile                              |   1 +
>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++

The '595 is already handled by drivers/gpio/gpio-74x164.c.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafał Miłecki Dec. 8, 2014, 2:47 p.m. UTC | #2
On 8 December 2014 at 15:41, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> Hi Rafał,
>
> On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>> SN54HC595 and SN74HC595 are devices based on shift registers controlled
>> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
>>
>> They are present on some Broadcom home router boards where manufacturer
>> needed few extra GPIOs.
>>
>> This driver simply uses specified GPIOs to control shift registers and
>> registers another GPIO chip. So you can call it a GPIO extender.
>>
>> Due to the hardware design only output direction is supported. Reading
>> values is handled using tiny internal cache.
>>
>> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
>> ---
>>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
>>  drivers/gpio/Kconfig                               |  11 ++
>>  drivers/gpio/Makefile                              |   1 +
>>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
>
> The '595 is already handled by drivers/gpio/gpio-74x164.c.

gpio-74x164.c seems to be tight closely to the SPI. In my case it's
GPIO-controller '595.

Do you have any other idea how we could handle this?
Geert Uytterhoeven Dec. 8, 2014, 3:03 p.m. UTC | #3
Hi Rafał,

On Mon, Dec 8, 2014 at 3:47 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
> On 8 December 2014 at 15:41, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>> On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>>> SN54HC595 and SN74HC595 are devices based on shift registers controlled
>>> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
>>>
>>> They are present on some Broadcom home router boards where manufacturer
>>> needed few extra GPIOs.
>>>
>>> This driver simply uses specified GPIOs to control shift registers and
>>> registers another GPIO chip. So you can call it a GPIO extender.
>>>
>>> Due to the hardware design only output direction is supported. Reading
>>> values is handled using tiny internal cache.
>>>
>>> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
>>> ---
>>>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
>>>  drivers/gpio/Kconfig                               |  11 ++
>>>  drivers/gpio/Makefile                              |   1 +
>>>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
>>
>> The '595 is already handled by drivers/gpio/gpio-74x164.c.
>
> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
> GPIO-controller '595.

Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
master controller, while your driver contains a very simple variant (without any
timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.

> Do you have any other idea how we could handle this?

Your driver does provide OE support, which gpio-74x164 doesn't support.
Perhaps that can be added to gpio-74x164 instead?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafał Miłecki Dec. 8, 2014, 3:23 p.m. UTC | #4
On 8 December 2014 at 16:03, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> Hi Rafał,
>
> On Mon, Dec 8, 2014 at 3:47 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>> On 8 December 2014 at 15:41, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>>> On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>>>> SN54HC595 and SN74HC595 are devices based on shift registers controlled
>>>> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
>>>>
>>>> They are present on some Broadcom home router boards where manufacturer
>>>> needed few extra GPIOs.
>>>>
>>>> This driver simply uses specified GPIOs to control shift registers and
>>>> registers another GPIO chip. So you can call it a GPIO extender.
>>>>
>>>> Due to the hardware design only output direction is supported. Reading
>>>> values is handled using tiny internal cache.
>>>>
>>>> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
>>>> ---
>>>>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
>>>>  drivers/gpio/Kconfig                               |  11 ++
>>>>  drivers/gpio/Makefile                              |   1 +
>>>>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
>>>
>>> The '595 is already handled by drivers/gpio/gpio-74x164.c.
>>
>> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
>> GPIO-controller '595.
>
> Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
> master controller, while your driver contains a very simple variant (without any
> timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.
>
>> Do you have any other idea how we could handle this?
>
> Your driver does provide OE support, which gpio-74x164 doesn't support.
> Perhaps that can be added to gpio-74x164 instead?

It's not the missing OE support in gpio-74x164 that worries me, but
the whole rest.

I would need to modify gpio-74x164 to:
1) Use another OF table with different entry
2) Use different probe function that doesn't take spi_device parameter
and doesn't do spi setup
3) Extend struct gen_74x164_chip to include GPIOs
4) Use totally different __gen_74x164_write_config

Amount of shared code would be so small I doubt it's worth it. Both
driver are quite trivial (200 or less LOC). Sharing:
1) ~5 lines long __gen_74x164_write_config
2) ~5 lines long gen_74x164_set_value
3) 1 line long gen_74x164_direction_output
makes me feel it's not really worth combining these two drivers into a one.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arnd Bergmann Dec. 8, 2014, 3:41 p.m. UTC | #5
On Monday 08 December 2014 16:23:01 Rafał Miłecki wrote:
> On 8 December 2014 at 16:03, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > Hi Rafał,
> >
> > On Mon, Dec 8, 2014 at 3:47 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
> >> On 8 December 2014 at 15:41, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >>> On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
> >>>> SN54HC595 and SN74HC595 are devices based on shift registers controlled
> >>>> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
> >>>>
> >>>> They are present on some Broadcom home router boards where manufacturer
> >>>> needed few extra GPIOs.
> >>>>
> >>>> This driver simply uses specified GPIOs to control shift registers and
> >>>> registers another GPIO chip. So you can call it a GPIO extender.
> >>>>
> >>>> Due to the hardware design only output direction is supported. Reading
> >>>> values is handled using tiny internal cache.
> >>>>
> >>>> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> >>>> ---
> >>>>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
> >>>>  drivers/gpio/Kconfig                               |  11 ++
> >>>>  drivers/gpio/Makefile                              |   1 +
> >>>>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
> >>>
> >>> The '595 is already handled by drivers/gpio/gpio-74x164.c.
> >>
> >> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
> >> GPIO-controller '595.
> >
> > Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
> > master controller, while your driver contains a very simple variant (without any
> > timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.
> >
> >> Do you have any other idea how we could handle this?
> >
> > Your driver does provide OE support, which gpio-74x164 doesn't support.
> > Perhaps that can be added to gpio-74x164 instead?
> 
> It's not the missing OE support in gpio-74x164 that worries me, but
> the whole rest.
> 
> I would need to modify gpio-74x164 to:
> 1) Use another OF table with different entry
> 2) Use different probe function that doesn't take spi_device parameter
> and doesn't do spi setup
> 3) Extend struct gen_74x164_chip to include GPIOs
> 4) Use totally different __gen_74x164_write_config

I think the suggestion was to use the spi-gpio driver in combination
with gpio-74x164.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafał Miłecki Dec. 8, 2014, 4:31 p.m. UTC | #6
On 8 December 2014 at 16:41, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 08 December 2014 16:23:01 Rafał Miłecki wrote:
>> On 8 December 2014 at 16:03, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>> > Hi Rafał,
>> >
>> > On Mon, Dec 8, 2014 at 3:47 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>> >> On 8 December 2014 at 15:41, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>> >>> On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>> >>>> SN54HC595 and SN74HC595 are devices based on shift registers controlled
>> >>>> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
>> >>>>
>> >>>> They are present on some Broadcom home router boards where manufacturer
>> >>>> needed few extra GPIOs.
>> >>>>
>> >>>> This driver simply uses specified GPIOs to control shift registers and
>> >>>> registers another GPIO chip. So you can call it a GPIO extender.
>> >>>>
>> >>>> Due to the hardware design only output direction is supported. Reading
>> >>>> values is handled using tiny internal cache.
>> >>>>
>> >>>> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
>> >>>> ---
>> >>>>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
>> >>>>  drivers/gpio/Kconfig                               |  11 ++
>> >>>>  drivers/gpio/Makefile                              |   1 +
>> >>>>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
>> >>>
>> >>> The '595 is already handled by drivers/gpio/gpio-74x164.c.
>> >>
>> >> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
>> >> GPIO-controller '595.
>> >
>> > Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
>> > master controller, while your driver contains a very simple variant (without any
>> > timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.
>> >
>> >> Do you have any other idea how we could handle this?
>> >
>> > Your driver does provide OE support, which gpio-74x164 doesn't support.
>> > Perhaps that can be added to gpio-74x164 instead?
>>
>> It's not the missing OE support in gpio-74x164 that worries me, but
>> the whole rest.
>>
>> I would need to modify gpio-74x164 to:
>> 1) Use another OF table with different entry
>> 2) Use different probe function that doesn't take spi_device parameter
>> and doesn't do spi setup
>> 3) Extend struct gen_74x164_chip to include GPIOs
>> 4) Use totally different __gen_74x164_write_config
>
> I think the suggestion was to use the spi-gpio driver in combination
> with gpio-74x164.

Oh, OK, I've obviously missed that.

I don't know... I'm somehow not really convinced to that, because
AFAIK there isn't any SPI master device between GPIOs and 'HC595. I
don't know if pretending there is some extra hardware (just to use
another Linux driver/layer) is a good idea. This would:
1) Not match hardware design
2) Involve some extra code.

I'm not even sure if this would work out-of-the box (without some
extra changes) at all. From early look at spi-gpio.c I can't see it
implementing everything I need for GPIO-connected 'HC595.
I think that implementing support for this extra SPI layer will
actually require more code/tricks than a separated driver.
Arnd Bergmann Dec. 8, 2014, 4:56 p.m. UTC | #7
On Monday 08 December 2014 17:31:45 Rafał Miłecki wrote:
> On 8 December 2014 at 16:41, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Monday 08 December 2014 16:23:01 Rafał Miłecki wrote:
> >> On 8 December 2014 at 16:03, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >> >> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
> >> >> GPIO-controller '595.
> >> >
> >> > Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
> >> > master controller, while your driver contains a very simple variant (without any
> >> > timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.
> >> >
> >> >> Do you have any other idea how we could handle this?
> >> >
> >> > Your driver does provide OE support, which gpio-74x164 doesn't support.
> >> > Perhaps that can be added to gpio-74x164 instead?
> >>
> >> It's not the missing OE support in gpio-74x164 that worries me, but
> >> the whole rest.
> >>
> >> I would need to modify gpio-74x164 to:
> >> 1) Use another OF table with different entry
> >> 2) Use different probe function that doesn't take spi_device parameter
> >> and doesn't do spi setup
> >> 3) Extend struct gen_74x164_chip to include GPIOs
> >> 4) Use totally different __gen_74x164_write_config
> >
> > I think the suggestion was to use the spi-gpio driver in combination
> > with gpio-74x164.
> 
> Oh, OK, I've obviously missed that.
> 
> I don't know... I'm somehow not really convinced to that, because
> AFAIK there isn't any SPI master device between GPIOs and 'HC595. I
> don't know if pretending there is some extra hardware (just to use
> another Linux driver/layer) is a good idea. This would:
> 1) Not match hardware design
> 2) Involve some extra code.
> 
> I'm not even sure if this would work out-of-the box (without some
> extra changes) at all. From early look at spi-gpio.c I can't see it
> implementing everything I need for GPIO-connected 'HC595.
> I think that implementing support for this extra SPI layer will
> actually require more code/tricks than a separated driver.

The purpose of the spi-gpio driver is to avoid having to write
two drivers for every spi slave device if someone wants to drive
it using bit-banged gpios.

The existing users of the driver are in fact all using spi-gpio,
see:
arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
arch/arm/boot/dts/imx28-cfa10049.dts

and in openwrt:
target/linux/brcm63xx/patches-3.14/501-board-NB4.patch
target/linux/brcm63xx/patches-3.14/526-board_CT6373-1.patch

so there shouldn't be too much missing, and extending spi-gpio
for any missing features would help other people trying to attach
random spi devices using gpio as well.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven Dec. 8, 2014, 4:59 p.m. UTC | #8
Hi Rafał,

On Mon, Dec 8, 2014 at 5:31 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
> On 8 December 2014 at 16:41, Arnd Bergmann <arnd@arndb.de> wrote:
>> On Monday 08 December 2014 16:23:01 Rafał Miłecki wrote:
>>> On 8 December 2014 at 16:03, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>>> > On Mon, Dec 8, 2014 at 3:47 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>>> >> On 8 December 2014 at 15:41, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>>> >>> On Mon, Dec 8, 2014 at 3:27 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>>> >>>> SN54HC595 and SN74HC595 are devices based on shift registers controlled
>>> >>>> with 5 input signals (serial-in) and providing 8 outputs (parallel-out).
>>> >>>>
>>> >>>> They are present on some Broadcom home router boards where manufacturer
>>> >>>> needed few extra GPIOs.
>>> >>>>
>>> >>>> This driver simply uses specified GPIOs to control shift registers and
>>> >>>> registers another GPIO chip. So you can call it a GPIO extender.
>>> >>>>
>>> >>>> Due to the hardware design only output direction is supported. Reading
>>> >>>> values is handled using tiny internal cache.
>>> >>>>
>>> >>>> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
>>> >>>> ---
>>> >>>>  .../devicetree/bindings/gpio/gpio-sn54hc595.txt    |  35 ++++
>>> >>>>  drivers/gpio/Kconfig                               |  11 ++
>>> >>>>  drivers/gpio/Makefile                              |   1 +
>>> >>>>  drivers/gpio/gpio-sn54hc595.c                      | 219 +++++++++++++++++++++
>>> >>>
>>> >>> The '595 is already handled by drivers/gpio/gpio-74x164.c.
>>> >>
>>> >> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
>>> >> GPIO-controller '595.
>>> >
>>> > Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
>>> > master controller, while your driver contains a very simple variant (without any
>>> > timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.
>>> >
>>> >> Do you have any other idea how we could handle this?
>>> >
>>> > Your driver does provide OE support, which gpio-74x164 doesn't support.
>>> > Perhaps that can be added to gpio-74x164 instead?
>>>
>>> It's not the missing OE support in gpio-74x164 that worries me, but
>>> the whole rest.
>>>
>>> I would need to modify gpio-74x164 to:
>>> 1) Use another OF table with different entry
>>> 2) Use different probe function that doesn't take spi_device parameter
>>> and doesn't do spi setup
>>> 3) Extend struct gen_74x164_chip to include GPIOs
>>> 4) Use totally different __gen_74x164_write_config
>>
>> I think the suggestion was to use the spi-gpio driver in combination
>> with gpio-74x164.
>
> Oh, OK, I've obviously missed that.
>
> I don't know... I'm somehow not really convinced to that, because
> AFAIK there isn't any SPI master device between GPIOs and 'HC595. I

There is: you implement SPI using bitbang on GPIOs.

> don't know if pretending there is some extra hardware (just to use
> another Linux driver/layer) is a good idea. This would:
> 1) Not match hardware design
> 2) Involve some extra code.
>
> I'm not even sure if this would work out-of-the box (without some
> extra changes) at all. From early look at spi-gpio.c I can't see it
> implementing everything I need for GPIO-connected 'HC595.

It should. Plenty of people have connected '595s to SPI buses (I did so
myself, too). Hint: connect chip select to the register clock.

> I think that implementing support for this extra SPI layer will
> actually require more code/tricks than a separated driver.

Yes, it will require more code, as spi-gpio is more generic than your simple
implementation.  But the end result is more flexible and reusable.

The only thing missing is the programmable OE and reset pins,
which are assumed hardwired by the gpio-74x164 driver.
These could be implemented using new gpio-oe and gpio-reset
properties.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Maxime Ripard Dec. 9, 2014, 9:09 a.m. UTC | #9
On Mon, Dec 08, 2014 at 05:56:56PM +0100, Arnd Bergmann wrote:
> On Monday 08 December 2014 17:31:45 Rafał Miłecki wrote:
> > On 8 December 2014 at 16:41, Arnd Bergmann <arnd@arndb.de> wrote:
> > > On Monday 08 December 2014 16:23:01 Rafał Miłecki wrote:
> > >> On 8 December 2014 at 16:03, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > >> >> gpio-74x164.c seems to be tight closely to the SPI. In my case it's
> > >> >> GPIO-controller '595.
> > >> >
> > >> > Right. gpio-74x164.c uses the SPI framework, so it will work with any SPI
> > >> > master controller, while your driver contains a very simple variant (without any
> > >> > timing constraints) of spi-gpio.c, and is limited to connecting to GPIO pins.
> > >> >
> > >> >> Do you have any other idea how we could handle this?
> > >> >
> > >> > Your driver does provide OE support, which gpio-74x164 doesn't support.
> > >> > Perhaps that can be added to gpio-74x164 instead?
> > >>
> > >> It's not the missing OE support in gpio-74x164 that worries me, but
> > >> the whole rest.
> > >>
> > >> I would need to modify gpio-74x164 to:
> > >> 1) Use another OF table with different entry
> > >> 2) Use different probe function that doesn't take spi_device parameter
> > >> and doesn't do spi setup
> > >> 3) Extend struct gen_74x164_chip to include GPIOs
> > >> 4) Use totally different __gen_74x164_write_config
> > >
> > > I think the suggestion was to use the spi-gpio driver in combination
> > > with gpio-74x164.
> > 
> > Oh, OK, I've obviously missed that.
> > 
> > I don't know... I'm somehow not really convinced to that, because
> > AFAIK there isn't any SPI master device between GPIOs and 'HC595. I
> > don't know if pretending there is some extra hardware (just to use
> > another Linux driver/layer) is a good idea. This would:
> > 1) Not match hardware design
> > 2) Involve some extra code.
> > 
> > I'm not even sure if this would work out-of-the box (without some
> > extra changes) at all. From early look at spi-gpio.c I can't see it
> > implementing everything I need for GPIO-connected 'HC595.
> > I think that implementing support for this extra SPI layer will
> > actually require more code/tricks than a separated driver.
> 
> The purpose of the spi-gpio driver is to avoid having to write
> two drivers for every spi slave device if someone wants to drive
> it using bit-banged gpios.
> 
> The existing users of the driver are in fact all using spi-gpio,
> see:
> arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
> arch/arm/boot/dts/imx28-cfa10049.dts

I'm the one who worked on the cfa10049, and yeah, it worked pretty
well at the time using spi-gpio.

We couldn't really do it any other way though, since we had another
SPI device tied to the same bus, so it really felt like this was the
right thing to do.

Maxime
Maxime Ripard Dec. 9, 2014, 9:12 a.m. UTC | #10
On Mon, Dec 08, 2014 at 05:59:11PM +0100, Geert Uytterhoeven wrote:
> > I think that implementing support for this extra SPI layer will
> > actually require more code/tricks than a separated driver.
> 
> Yes, it will require more code, as spi-gpio is more generic than your simple
> implementation.  But the end result is more flexible and reusable.
> 
> The only thing missing is the programmable OE and reset pins,
> which are assumed hardwired by the gpio-74x164 driver.
> These could be implemented using new gpio-oe and gpio-reset
> properties.

From my (very) vague memories of it, OE was actually supported by
using it as spi-gpio's chip select.

So I'd say that only the gpio-reset should be implemented.

Maxime
Rafał Miłecki Dec. 11, 2014, 10:36 a.m. UTC | #11
On 9 December 2014 at 10:12, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Mon, Dec 08, 2014 at 05:59:11PM +0100, Geert Uytterhoeven wrote:
>> > I think that implementing support for this extra SPI layer will
>> > actually require more code/tricks than a separated driver.
>>
>> Yes, it will require more code, as spi-gpio is more generic than your simple
>> implementation.  But the end result is more flexible and reusable.
>>
>> The only thing missing is the programmable OE and reset pins,
>> which are assumed hardwired by the gpio-74x164 driver.
>> These could be implemented using new gpio-oe and gpio-reset
>> properties.
>
> From my (very) vague memories of it, OE was actually supported by
> using it as spi-gpio's chip select.
>
> So I'd say that only the gpio-reset should be implemented.

I've tracked how spi_bitbang_transfer_one does work. Long story short it does:
bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
bitbang->txrx_bufs(spi, t);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);

txrx_bufs is a pointer to one of:
bitbang_txrx_be_cpha0
bitbang_txrx_be_cpha1


Now, in cpha[01] for every register bit we call:
1) setmosi - to set data, so it's serial (SER)
2) setsck - to shift bits, so it's shift register clock (SRCLK)

Then in spi_gpio_chipselect we call:
1) cs_gpios[chip], so it's register clock (RCLK)


As you can see, we don't call OE in spi_gpio_chipselect. So currently
both input signals and unhandled: OE and SRCLR. Luckily for me, it
appears my bootloader puts them in a wanted state, but this still
should be handled somehow.
Geert Uytterhoeven Dec. 11, 2014, 11:03 a.m. UTC | #12
On Thu, Dec 11, 2014 at 11:36 AM, Rafał Miłecki <zajec5@gmail.com> wrote:
> On 9 December 2014 at 10:12, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> On Mon, Dec 08, 2014 at 05:59:11PM +0100, Geert Uytterhoeven wrote:
>>> > I think that implementing support for this extra SPI layer will
>>> > actually require more code/tricks than a separated driver.
>>>
>>> Yes, it will require more code, as spi-gpio is more generic than your simple
>>> implementation.  But the end result is more flexible and reusable.
>>>
>>> The only thing missing is the programmable OE and reset pins,
>>> which are assumed hardwired by the gpio-74x164 driver.
>>> These could be implemented using new gpio-oe and gpio-reset
>>> properties.
>>
>> From my (very) vague memories of it, OE was actually supported by
>> using it as spi-gpio's chip select.
>>
>> So I'd say that only the gpio-reset should be implemented.
>
> I've tracked how spi_bitbang_transfer_one does work. Long story short it does:

[deleted standard SPI protocol]

> As you can see, we don't call OE in spi_gpio_chipselect. So currently
> both input signals and unhandled: OE and SRCLR. Luckily for me, it
> appears my bootloader puts them in a wanted state, but this still
> should be handled somehow.

I think you can just add two properties (one array for OE, one for SRCLR)
to the bindings for the gpio-74x164 driver, so it can set those GPIO pins,
if present. Note that they should be arrays, as gpio-74x164 supports\
daisy-chaining chips.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/gpio/gpio-sn54hc595.txt b/Documentation/devicetree/bindings/gpio/gpio-sn54hc595.txt
new file mode 100644
index 0000000..034e490
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-sn54hc595.txt
@@ -0,0 +1,35 @@ 
+GPIO controller based on SN54HC595 / SN74HC595 shift registers
+==============================================================
+
+Required properties:
+
+- compatible : ti,sn54hc595
+
+- ser-gpios : GPIO connected to the serial (SER) input
+
+- srclk-gpios : GPIO connected to the shift register clock (SRCLK) input
+
+- srclr-gpios : GPIO connected to the overriding clear (SRCLR) input
+
+- rclk-gpios : GPIO connected to the register clock (RCLK) input
+
+- oe-gpios : GPIO connected to the output-enable (OE) input
+
+- gpio-controller: Marks the device node as a GPIO controller.
+
+- #gpio-cells : Should be two. Pin number and the optional parameters.
+
+Example:
+
+	sn54hc595 {
+		compatible = "ti,sn54hc595";
+
+		ser-gpios = <&gpio0 3 0>;
+		srclk-gpios = <&gpio0 4 0>;
+		srclr-gpios = <&gpio0 5 0>;
+		rclk-gpios = <&gpio0 6 0>;
+		oe-gpios = <&gpio0 7 0>;
+
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0959ca9..3250870 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -457,6 +457,17 @@  config GPIO_TB10X
 	select GENERIC_IRQ_CHIP
 	select OF_GPIO
 
+comment "GPIO to GPIO expanders:"
+
+config GPIO_SN54HC595
+	tristate "SN54HC595 / SN74HC595 SIPO shift register"
+	depends on OF
+	help
+	  The 'HC595 devices contain 8 shift registers and are controlled using
+	  5 input signals.
+	  This driver controls inputs with 5 GPIOs and registers GPIO chip with
+	  8 outputs.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_ARIZONA
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index e5d346c..37be84d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -74,6 +74,7 @@  obj-$(CONFIG_GPIO_SAMSUNG)	+= gpio-samsung.o
 obj-$(CONFIG_ARCH_SA1100)	+= gpio-sa1100.o
 obj-$(CONFIG_GPIO_SCH)		+= gpio-sch.o
 obj-$(CONFIG_GPIO_SCH311X)	+= gpio-sch311x.o
+obj-$(CONFIG_GPIO_SN54HC595)	+= gpio-sn54hc595.o
 obj-$(CONFIG_GPIO_SODAVILLE)	+= gpio-sodaville.o
 obj-$(CONFIG_GPIO_SPEAR_SPICS)	+= gpio-spear-spics.o
 obj-$(CONFIG_GPIO_STA2X11)	+= gpio-sta2x11.o
diff --git a/drivers/gpio/gpio-sn54hc595.c b/drivers/gpio/gpio-sn54hc595.c
new file mode 100644
index 0000000..9ff4c3b
--- /dev/null
+++ b/drivers/gpio/gpio-sn54hc595.c
@@ -0,0 +1,219 @@ 
+/*
+ * Driver for SN54HC595 / SN74HC595 devices.
+ *
+ * Copyright (C) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define SN54HC595_NUM_GPIOS		8
+
+struct sn54hc595 {
+	struct gpio_chip	gpio_chip;
+
+	int			values[SN54HC595_NUM_GPIOS];
+
+	unsigned		ser;
+	unsigned		srclk;
+	unsigned		srclr;
+	unsigned		rclk;
+	unsigned		oe;
+};
+
+static inline struct sn54hc595 *gpio_chip_to_sn54hc595(struct gpio_chip *chip)
+{
+	return container_of(chip, struct sn54hc595, gpio_chip);
+}
+
+static void sn54hc595_update_values(struct sn54hc595 *sn54hc595)
+{
+	int i;
+
+	for (i = 0; i < SN54HC595_NUM_GPIOS; i++) {
+		gpio_set_value(sn54hc595->ser, sn54hc595->values[i]);
+
+		gpio_set_value(sn54hc595->srclk, 1);
+		gpio_set_value(sn54hc595->srclk, 0);
+	}
+
+	gpio_set_value(sn54hc595->rclk, 1);
+	gpio_set_value(sn54hc595->rclk, 0);
+}
+
+static int sn54hc595_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	return -ENOTSUPP;
+}
+
+static int sn54hc595_direction_output(struct gpio_chip *chip, unsigned gpio,
+				      int value)
+{
+	struct sn54hc595 *sn54hc595 = gpio_chip_to_sn54hc595(chip);
+
+	sn54hc595->values[gpio] = value;
+	sn54hc595_update_values(sn54hc595);
+
+	return 0;
+}
+
+static int sn54hc595_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+	struct sn54hc595 *sn54hc595 = gpio_chip_to_sn54hc595(chip);
+
+	return sn54hc595->values[gpio];
+}
+
+static void sn54hc595_set_value(struct gpio_chip *chip, unsigned gpio,
+				int value)
+{
+	struct sn54hc595 *sn54hc595 = gpio_chip_to_sn54hc595(chip);
+
+	sn54hc595->values[gpio] = value;
+	sn54hc595_update_values(sn54hc595);
+}
+
+static int sn54hc595_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct sn54hc595 *sn54hc595;
+	int err;
+
+	sn54hc595 = devm_kzalloc(dev, sizeof(*sn54hc595), GFP_KERNEL);
+	if (!sn54hc595)
+		return -ENOMEM;
+
+	sn54hc595->ser = of_get_named_gpio_flags(np, "ser-gpios", 0, NULL);
+	if (sn54hc595->ser < 0) {
+		dev_err(dev, "Couldn't read \"src\" property from the DT\n");
+		return -EINVAL;
+	}
+
+	sn54hc595->srclk = of_get_named_gpio_flags(np, "srclk-gpios", 0, NULL);
+	if (sn54hc595->srclk < 0) {
+		dev_err(dev, "Couldn't read \"srclk\" property from the DT\n");
+		return -EINVAL;
+	}
+
+	sn54hc595->srclr = of_get_named_gpio_flags(np, "srclr-gpios", 0, NULL);
+	if (sn54hc595->srclr < 0) {
+		dev_err(dev, "Couldn't read \"srclr\" property from the DT\n");
+		return -EINVAL;
+	}
+
+	sn54hc595->rclk = of_get_named_gpio_flags(np, "rclk-gpios", 0, NULL);
+	if (sn54hc595->rclk < 0) {
+		dev_err(dev, "Couldn't read \"rclk\" property from the DT\n");
+		return -EINVAL;
+	}
+
+	sn54hc595->oe = of_get_named_gpio_flags(np, "oe-gpios", 0, NULL);
+	if (sn54hc595->oe < 0) {
+		dev_err(dev, "Couldn't read \"oe\" property from the DT\n");
+		return -EINVAL;
+	}
+
+	if (devm_gpio_request(dev, sn54hc595->ser, dev_name(dev))) {
+		dev_err(dev, "Couldn't request GPIO %u\n", sn54hc595->ser);
+		return -EBUSY;
+	}
+
+	if (devm_gpio_request(dev, sn54hc595->srclk, dev_name(dev))) {
+		dev_err(dev, "Couldn't request GPIO %u\n", sn54hc595->srclk);
+		return -EBUSY;
+	}
+
+	if (devm_gpio_request(dev, sn54hc595->srclr, dev_name(dev))) {
+		dev_err(dev, "Couldn't request GPIO %u\n", sn54hc595->srclr);
+		return -EBUSY;
+	}
+
+	if (devm_gpio_request(dev, sn54hc595->rclk, dev_name(dev))) {
+		dev_err(dev, "Couldn't request GPIO %u\n", sn54hc595->rclk);
+		return -EBUSY;
+	}
+
+	if (devm_gpio_request(dev, sn54hc595->oe, dev_name(dev))) {
+		dev_err(dev, "Couldn't request GPIO %u\n", sn54hc595->oe);
+		return -EBUSY;
+	}
+
+	/* Get ready for raising shift clock and shifting values */
+	if (gpio_direction_output(sn54hc595->srclk, 0)) {
+		dev_err(dev, "Couldn't set \"srclk\" GPIO directon\n");
+		return -EIO;
+	}
+
+	/* Get ready for raising storage clock and load (copy) data */
+	if (gpio_direction_output(sn54hc595->rclk, 0)) {
+		dev_err(dev, "Couldn't set \"rclk\" GPIO directon\n");
+		return -EIO;
+	}
+
+	/* Enable outputs */
+	if (gpio_direction_output(sn54hc595->oe, 0)) {
+		dev_err(dev, "Couldn't set \"oe\" GPIO directon\n");
+		return -EIO;
+	}
+
+	/* Don't clear shift register */
+	if (gpio_direction_output(sn54hc595->srclr, 1)) {
+		dev_err(dev, "Couldn't set \"srclr\" GPIO directon\n");
+		return -EIO;
+	}
+
+	sn54hc595->gpio_chip.dev = dev;
+	sn54hc595->gpio_chip.label = "sn54hc595";
+	sn54hc595->gpio_chip.direction_input = sn54hc595_direction_input;
+	sn54hc595->gpio_chip.direction_output = sn54hc595_direction_output;
+	sn54hc595->gpio_chip.get = sn54hc595_get_value;
+	sn54hc595->gpio_chip.set = sn54hc595_set_value;
+	sn54hc595->gpio_chip.base = -1;
+	sn54hc595->gpio_chip.ngpio = SN54HC595_NUM_GPIOS;
+
+	err = gpiochip_add(&sn54hc595->gpio_chip);
+	if (err)
+		return err;
+
+	platform_set_drvdata(pdev, sn54hc595);
+
+	return 0;
+}
+
+static int sn54hc595_remove(struct platform_device *pdev)
+{
+	struct sn54hc595 *sn54hc595 = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&sn54hc595->gpio_chip);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+
+static const struct of_device_id sn54hc595_of_match[] = {
+	{ .compatible = "ti,sn54hc595", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
+
+static struct platform_driver sn54hc595_driver = {
+	.probe		= sn54hc595_probe,
+	.remove		= sn54hc595_remove,
+	.driver		= {
+		.name	= "sn54hc595",
+		.of_match_table = sn54hc595_of_match,
+	},
+};
+
+module_platform_driver(sn54hc595_driver);
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL");