Skip to contentSkip to conversation

Add initial support for Broadcom Cygnus SoC

PATCH Superseded Scott Branden 23 participants 265 messages Oct 8, 2014 – Dec 22, 2015 1 message not in the archive Page 2 of 2

Subsystems (20)
lore
Share & tools
lore
author maintainer
#153 lore raw

v2 cover pwm: kona: Drivers fixes

In reply to a message not in the archive

This patchset contains fixes for Broadcom's Kona PWM driver.

These changes fix glitch issues when changing settings on different channels. Kconfig change made to allow the driver to work on any Broadcom SoC rather than just mobile devices.

Arun Ramamurthy (4):
pwm: kona: Remove setting default smooth type and polarity for all
channels
pwm: kona: Fix incorrect enable after channel polarity change
pwm: kona: Fix enable, disable and config procedures
pwm: kona: Update dependency to ARCH_BCM

 drivers/pwm/Kconfig        |   2 +-
 drivers/pwm/pwm-bcm-kona.c | 112 ++++++++++++++++++++++++++++++++-------------
 2 files changed, 81 insertions(+), 33 deletions(-)
Signature · 1 line
2.1.3
author maintainer
#154 lore raw

PATCH v2 1/4 pwm: kona: Remove setting default smooth type and polarity for all channels

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same time the backlight turns on. The smooth type and polarity should be set individually for each channel as required and no defaults need to be set.

---
 drivers/pwm/pwm-bcm-kona.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +2 -5
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	/* Set smooth mode, push/pull, and normal polarity for all channels */
-	for (chan = 0; chan < kp->chip.npwm; chan++) {
-		value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+	/* Set push/pull for all channels */
+	for (chan = 0; chan < kp->chip.npwm; chan++)
 		value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-		value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-	}
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
Signature · 1 line
2.1.3
#155 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 6 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same time the backlight turns on. The smooth type and polarity should be set individually for each channel as required and no defaults need to be set.

I am guessing you are talking about a PWM controlled beeper/buzzer.

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

Quoted 16 lines
---
 drivers/pwm/pwm-bcm-kona.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -0
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device *pdev)
                return ret;
        }
 

drivers/pwm/pwm-bcm-kona.c static int kona_pwmc_probe(struct platform_device *pdev) · line 273

Quoted 10 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
-       /* Set smooth mode, push/pull, and normal polarity for all channels */
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
 
        writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

#156 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 10 lines · Tim Kryger
Quoted 6 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same time the backlight turns on. The smooth type and polarity should be set individually for each channel as required and no defaults need to be set.

I am guessing you are talking about a PWM controlled beeper/buzzer.

This change is more so to remove setting smooth type and polarity for all channels during probe and to leave them as their default values. Infact, setting the PWM_CONTROL_TYPE_SHIT is also redundant cause the default value is already 1 for all channels. We can remove that loop entirely and this will be done in the next patch set. The smooth type and polarity are only changed when the particular pwm channel is enabled or polarity is changed.

Quoted 4 lines

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

We observe this on the bcm958300K board where one of the PWM channels is connected to the buzzer and changing the smooth type and polarity from its default values causes a click

Quoted 25 lines
Quoted 25 lines
---
  drivers/pwm/pwm-bcm-kona.c | 7 ++-----
  1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +2 -5
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device *pdev)
                 return ret;
         }
 
-       /* Set smooth mode, push/pull, and normal polarity for all channels */
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                 value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
 
Quoted 5 lines

drivers/pwm/pwm-bcm-kona.c static int kona_pwmc_probe(struct platform_device *pdev) · line 273

Quoted 1 line
drivers/pwm/pwm-bcm-kona.c +0 -0
         writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

The default value for polarity is 0 which is normal polarity, so setting it to 1 here in the probe function without a sysfs call is when the software will report the polarity as normal when it is actually inversed.

Quoted 5 lines

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

I agree with you about the sysfs case Tim, but since this is the probe function and not a sysfs callback, should we not leave it as the default value?

#157 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 26 lines · Arun Ramamurthy
Quoted 14 lines · Tim Kryger
Quoted 9 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same
time the backlight turns on. The smooth type and polarity should be set individually
for each channel as required and no defaults need to be set.

Quoted 2 lines

I am guessing you are talking about a PWM controlled beeper/buzzer.

This change is more so to remove setting smooth type and polarity for all channels during probe and to leave them as their default values. Infact, setting the PWM_CONTROL_TYPE_SHIT is also redundant cause the default value is already 1 for all channels. We can remove that loop entirely and this will be done in the next patch set. The smooth type and polarity are only changed when the particular pwm channel is enabled or polarity is changed.

Quoted 8 lines
Quoted 4 lines

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

We observe this on the bcm958300K board where one of the PWM channels is connected to the buzzer and changing the smooth type and polarity from its default values causes a click

Which of these two bits is causing the click?

I've already said that I'm open to removing the smooth bit here if that helps.

Quoted 33 lines
Quoted 27 lines
Quoted 27 lines
---
  drivers/pwm/pwm-bcm-kona.c | 7 ++-----
  1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -1
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device
 *pdev)
                 return ret;
         }
 
-       /* Set smooth mode, push/pull, and normal polarity for all

channels */

drivers/pwm/pwm-bcm-kona.c +2 -4
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                 value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
Quoted 6 lines
Quoted 1 line
         writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

Quoted 4 lines

The default value for polarity is 0 which is normal polarity, so setting it to 1 here in the probe function without a sysfs call is
when the software will report the polarity as normal when it is actually inversed.

Please double check the meaning of the polarity bits for the revision of PWM IP in your chip. I suspect you are mistaken here.

This driver is for PWM blocks compatible those found in bcm28145, bcm28155, bcm21664, and other mobile chips of that generation.

Apparently in contrast to the chip you are using, a set polarity bit in the control register means normal polarity for the chips I mentioned.

A default of zero for these bits means they must be set to meet the PWM framework's expectation that channels begin with normal polarity.

Quoted 10 lines
Quoted 7 lines

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

I agree with you about the sysfs case Tim, but since this is the probe function and not a sysfs callback, should we not leave it as the default value?

#158 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 32 lines · Tim Kryger
Quoted 30 lines · Arun Ramamurthy
Quoted 14 lines · Tim Kryger
Quoted 9 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same
time the backlight turns on. The smooth type and polarity should be set individually
for each channel as required and no defaults need to be set.

Quoted 2 lines

I am guessing you are talking about a PWM controlled beeper/buzzer.

This change is more so to remove setting smooth type and polarity for all channels during probe and to leave them as their default values. Infact, setting the PWM_CONTROL_TYPE_SHIT is also redundant cause the default value is already 1 for all channels. We can remove that loop entirely and this will be done in the next patch set. The smooth type and polarity are only changed when the particular pwm channel is enabled or polarity is changed.

Quoted 4 lines

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

Quoted 9 lines
Quoted 4 lines

We observe this on the bcm958300K board where one of the PWM channels is connected to the buzzer and changing the smooth type and polarity from its default values causes a click

Which of these two bits is causing the click?

I've already said that I'm open to removing the smooth bit here if that helps.

Thank you for your quick reply Tim. It is setting the polarity bit that causes the click. I am planning on removing this entire loop in the next patch set, are you okay with that?

Quoted 44 lines
Quoted 33 lines
Quoted 27 lines
Quoted 27 lines
---
   drivers/pwm/pwm-bcm-kona.c | 7 ++-----
   1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -1
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device
 *pdev)
                  return ret;
          }
 
-       /* Set smooth mode, push/pull, and normal polarity for all

channels */

drivers/pwm/pwm-bcm-kona.c +2 -4
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                  value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
Quoted 6 lines
Quoted 1 line
          writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

Quoted 4 lines

The default value for polarity is 0 which is normal polarity, so setting it to 1 here in the probe function without a sysfs call is
when the software will report the polarity as normal when it is actually inversed.

Please double check the meaning of the polarity bits for the revision of PWM IP in your chip. I suspect you are mistaken here.

This driver is for PWM blocks compatible those found in bcm28145, bcm28155, bcm21664, and other mobile chips of that generation.

Quoted 7 lines

Apparently in contrast to the chip you are using, a set polarity bit in the control register means normal polarity for the chips I mentioned.

A default of zero for these bits means they must be set to meet the PWM framework's expectation that channels begin with normal polarity.

Tim, this is from the RDB of our new chip which is supposed to have the same IP as the mobile chip sets you mentioned:

When set to 1 the output polarity for the PWM Output signal will be active hight; When set to 0, the output polarity for the PWM Output signal will be active low. Default State is 0.

My understanding is that the frameworks normal polarity means active low, am I mistaken in that?

Quoted 10 lines
Quoted 10 lines
Quoted 7 lines

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

I agree with you about the sysfs case Tim, but since this is the probe function and not a sysfs callback, should we not leave it as the default value?

#159 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 47 lines · Arun Ramamurthy
Quoted 44 lines · Tim Kryger
Quoted 40 lines · Arun Ramamurthy
Quoted 17 lines · Tim Kryger
Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same
time the backlight turns on. The smooth type and polarity should be set individually
for each channel as required and no defaults need to be set.

Quoted 2 lines

I am guessing you are talking about a PWM controlled beeper/buzzer.

This change is more so to remove setting smooth type and polarity for all channels during probe and to leave them as their default values. Infact, setting the PWM_CONTROL_TYPE_SHIT is also redundant cause the default value
is already 1 for all channels. We can remove that loop entirely and this will be done in the next patch set. The smooth type and polarity are only changed when the particular pwm channel is enabled or polarity is changed.

Quoted 4 lines

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

We observe this on the bcm958300K board where one of the PWM channels is connected to the buzzer and changing the smooth type and polarity from its default values causes a click

Quoted 8 lines
Quoted 5 lines

Which of these two bits is causing the click?

I've already said that I'm open to removing the smooth bit here if that helps.

Thank you for your quick reply Tim. It is setting the polarity bit that causes the click. I am planning on removing this entire loop in the next patch set, are you okay with that?

Does it cause a click at this moment or at a later point in time?

Is the click your sole motivation for this series? If so, can you propose a more targeted fix?

I would be amenable to deferring polarity changes until subsequent enable operations:

- kona_pwmc_probe doesn't do any hardware writes
- kona_pwmc_set_polarity only updates a polarity variable
- kona_pwmc_enable sets hardware polarity according to the variable

Would this be sufficient to satisfy your needs?

I am still worried that deferring polarity changes may negatively impact some PWM users who set polarity but don't immediately enable the PWM.

Quoted 57 lines
Quoted 47 lines
Quoted 34 lines
Quoted 27 lines
Quoted 27 lines
---
   drivers/pwm/pwm-bcm-kona.c | 7 ++-----
   1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -1
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device
 *pdev)
                  return ret;
          }
 
-       /* Set smooth mode, push/pull, and normal polarity for all

channels */

drivers/pwm/pwm-bcm-kona.c +2 -4
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                  value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
Quoted 7 lines
Quoted 1 line
          writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

Quoted 5 lines

The default value for polarity is 0 which is normal polarity, so setting it
to 1 here in the probe function without a sysfs call is
when the software will report the polarity as normal when it is actually inversed.

Please double check the meaning of the polarity bits for the revision of PWM IP in your chip. I suspect you are mistaken here.

This driver is for PWM blocks compatible those found in bcm28145, bcm28155, bcm21664, and other mobile chips of that generation.

Quoted 7 lines

Apparently in contrast to the chip you are using, a set polarity bit in the control register means normal polarity for the chips I mentioned.

A default of zero for these bits means they must be set to meet the PWM framework's expectation that channels begin with normal polarity.

Tim, this is from the RDB of our new chip which is supposed to have the same IP as the mobile chip sets you mentioned:

Quoted 6 lines

When set to 1 the output polarity for the PWM Output signal will be active hight; When set to 0, the output polarity for the PWM Output signal will be active low. Default State is 0.

My understanding is that the frameworks normal polarity means active low, am I mistaken in that?

That is not how I would interpret things.

Perhaps this paragraph from Documentation/pwm.txt will help you:

When implementing polarity support in a PWM driver, make sure to respect the signal conventions in the PWM framework. By definition, normal polarity characterizes a signal starts high for the duration of the duty cycle and goes low for the remainder of the period. Conversely, a signal with inversed polarity starts low for the duration of the duty cycle and goes high for the remainder of the period.

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 8 lines

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

I agree with you about the sysfs case Tim, but since this is the probe function and not a sysfs callback, should we not leave it as the default value?

#160 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 63 lines · Tim Kryger
Quoted 47 lines · Arun Ramamurthy
Quoted 44 lines · Tim Kryger
Quoted 40 lines · Arun Ramamurthy
Quoted 17 lines · Tim Kryger
Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same
time the backlight turns on. The smooth type and polarity should be set individually
for each channel as required and no defaults need to be set.

Quoted 2 lines

I am guessing you are talking about a PWM controlled beeper/buzzer.

This change is more so to remove setting smooth type and polarity for all channels during probe and to leave them as their default values. Infact, setting the PWM_CONTROL_TYPE_SHIT is also redundant cause the default value
is already 1 for all channels. We can remove that loop entirely and this will be done in the next patch set. The smooth type and polarity are only changed when the particular pwm channel is enabled or polarity is changed.

Quoted 4 lines

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

We observe this on the bcm958300K board where one of the PWM channels is connected to the buzzer and changing the smooth type and polarity from its default values causes a click

Quoted 8 lines
Quoted 5 lines

Which of these two bits is causing the click?

I've already said that I'm open to removing the smooth bit here if that helps.

Thank you for your quick reply Tim. It is setting the polarity bit that causes the click. I am planning on removing this entire loop in the next patch set, are you okay with that?

Does it cause a click at this moment or at a later point in time?

Is the click your sole motivation for this series? If so, can you propose a more targeted fix?

Quoted 9 lines

I would be amenable to deferring polarity changes until subsequent enable operations:

- kona_pwmc_probe doesn't do any hardware writes
- kona_pwmc_set_polarity only updates a polarity variable
- kona_pwmc_enable sets hardware polarity according to the variable

Would this be sufficient to satisfy your needs?

It clicks at time of boot up, I can agree to the above changes and will update the next patch set accordingly.

Quoted 70 lines

I am still worried that deferring polarity changes may negatively impact some PWM users who set polarity but don't immediately enable the PWM.

Quoted 57 lines
Quoted 47 lines
Quoted 34 lines
Quoted 27 lines
Quoted 27 lines
---
    drivers/pwm/pwm-bcm-kona.c | 7 ++-----
    1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -1
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device
 *pdev)
                   return ret;
           }
 
-       /* Set smooth mode, push/pull, and normal polarity for all

channels */

drivers/pwm/pwm-bcm-kona.c +2 -4
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                   value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
Quoted 7 lines
Quoted 1 line
           writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

Quoted 5 lines

The default value for polarity is 0 which is normal polarity, so setting it
to 1 here in the probe function without a sysfs call is
when the software will report the polarity as normal when it is actually inversed.

Please double check the meaning of the polarity bits for the revision of PWM IP in your chip. I suspect you are mistaken here.

This driver is for PWM blocks compatible those found in bcm28145, bcm28155, bcm21664, and other mobile chips of that generation.

Quoted 7 lines

Apparently in contrast to the chip you are using, a set polarity bit in the control register means normal polarity for the chips I mentioned.

A default of zero for these bits means they must be set to meet the PWM framework's expectation that channels begin with normal polarity.

Tim, this is from the RDB of our new chip which is supposed to have the same IP as the mobile chip sets you mentioned:

Quoted 6 lines

When set to 1 the output polarity for the PWM Output signal will be active hight; When set to 0, the output polarity for the PWM Output signal will be active low. Default State is 0.

My understanding is that the frameworks normal polarity means active low, am I mistaken in that?

That is not how I would interpret things.

Quoted 9 lines

Perhaps this paragraph from Documentation/pwm.txt will help you:

When implementing polarity support in a PWM driver, make sure to respect the signal conventions in the PWM framework. By definition, normal polarity characterizes a signal starts high for the duration of the duty cycle and goes low for the remainder of the period. Conversely, a signal with inversed polarity starts low for the duration of the duty cycle and goes high for the remainder of the period.

I had it mixed up, I will update the polarity to match the PWM framework.

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 8 lines

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

I agree with you about the sysfs case Tim, but since this is the probe function and not a sysfs callback, should we not leave it as the default value?

#161 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

In reply to Tim Kryger

Hi Tim,

I'm going to take over this submission because I made the changes to the driver. Arun was filling in for me while I was on leave. Now I'm back and I think I can help clarify why these changes were made. A summary for all the changes should help.

There were two problems. First was a problem caused by setting the polarity in probe. It caused the speaker to click when the polarity was set so we took that out as it didn't seem to serve any useful purpose that I could see. The polarity changes should be made in the polarity callback.

The second and bigger problem was the smooth type sequence. If it isn't done according to the spec then one in ten or twenty times you won't even get a signal when it's enabled. Following the correct sequence with the 400 ns delays solves this problem.

Additionally, by not following the sequence you won't get a smooth transition. You'll get a change in the settings (duty cycle, period) but may get a non smooth transition. So it's important to follow the spec here. We don't want non-smooth transitions.

More comments below.

Quoted 142 lines · Tim Kryger
Quoted 47 lines · Arun Ramamurthy
Quoted 44 lines · Tim Kryger
Quoted 40 lines · Arun Ramamurthy
Quoted 17 lines · Tim Kryger
Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The probe routine unnecessarily sets the smooth type and polarity for all channels. This causes the channel for the speaker to click at the same
time the backlight turns on. The smooth type and polarity should be set individually
for each channel as required and no defaults need to be set.

Quoted 2 lines

I am guessing you are talking about a PWM controlled beeper/buzzer.

This change is more so to remove setting smooth type and polarity for all channels during probe and to leave them as their default values. Infact, setting the PWM_CONTROL_TYPE_SHIT is also redundant cause the default value
is already 1 for all channels. We can remove that loop entirely and this will be done in the next patch set. The smooth type and polarity are only changed when the particular pwm channel is enabled or polarity is changed.

Quoted 4 lines

Can you mention what board you are observing this issue on?

Also please explain why setting these bits result in an audible click.

We observe this on the bcm958300K board where one of the PWM channels is connected to the buzzer and changing the smooth type and polarity from its default values causes a click

Quoted 8 lines
Quoted 5 lines

Which of these two bits is causing the click?

I've already said that I'm open to removing the smooth bit here if that helps.

Thank you for your quick reply Tim. It is setting the polarity bit that causes the click. I am planning on removing this entire loop in the next patch set, are you okay with that?

Does it cause a click at this moment or at a later point in time?

Is the click your sole motivation for this series? If so, can you propose a more targeted fix?

I would be amenable to deferring polarity changes until subsequent enable operations:

- kona_pwmc_probe doesn't do any hardware writes
- kona_pwmc_set_polarity only updates a polarity variable
- kona_pwmc_enable sets hardware polarity according to the variable

Would this be sufficient to satisfy your needs?

I am still worried that deferring polarity changes may negatively impact some PWM users who set polarity but don't immediately enable the PWM.

Quoted 57 lines
Quoted 47 lines
Quoted 34 lines
Quoted 27 lines
Quoted 27 lines
---
   drivers/pwm/pwm-bcm-kona.c | 7 ++-----
   1 file changed, 2 insertions(+), 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -1
index 02bc048..29eef9e 100644
@@ -266,12 +266,9 @@ static int kona_pwmc_probe(struct platform_device
 *pdev)
                  return ret;
          }
 
-       /* Set smooth mode, push/pull, and normal polarity for all

channels */

drivers/pwm/pwm-bcm-kona.c +2 -4
-       for (chan = 0; chan < kp->chip.npwm; chan++) {
-               value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+       /* Set push/pull for all channels */
+       for (chan = 0; chan < kp->chip.npwm; chan++)
                  value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-               value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-       }
Quoted 7 lines
Quoted 1 line
          writel(value, kp->base + PWM_CONTROL_OFFSET);

While the smooth bit need not be set here, it is important that the polarity bit be set.

Quoted 5 lines

The default value for polarity is 0 which is normal polarity, so setting it
to 1 here in the probe function without a sysfs call is
when the software will report the polarity as normal when it is actually inversed.

Please double check the meaning of the polarity bits for the revision of PWM IP in your chip. I suspect you are mistaken here.

This driver is for PWM blocks compatible those found in bcm28145, bcm28155, bcm21664, and other mobile chips of that generation.

Quoted 7 lines

Apparently in contrast to the chip you are using, a set polarity bit in the control register means normal polarity for the chips I mentioned.

A default of zero for these bits means they must be set to meet the PWM framework's expectation that channels begin with normal polarity.

Tim, this is from the RDB of our new chip which is supposed to have the same IP as the mobile chip sets you mentioned:

Quoted 6 lines

When set to 1 the output polarity for the PWM Output signal will be active hight; When set to 0, the output polarity for the PWM Output signal will be active low. Default State is 0.

My understanding is that the frameworks normal polarity means active low, am I mistaken in that?

That is not how I would interpret things.

Quoted 9 lines

Perhaps this paragraph from Documentation/pwm.txt will help you:

When implementing polarity support in a PWM driver, make sure to respect the signal conventions in the PWM framework. By definition, normal polarity characterizes a signal starts high for the duration of the duty cycle and goes low for the remainder of the period. Conversely, a signal with inversed polarity starts low for the duration of the duty cycle and goes high for the remainder of the period.

Agreed. When using DT, the polarity will be set properly. When using sysfs there is a discrepancy and this needs to be addressed. Because the hw default is active low, the polarity will be inversed when the sysfs says polarity is "normal". I'll have to account for this in the driver.

Quoted 17 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 8 lines

Otherwise software will report the polarity as normal when it it is actually inversed.

Consider the case where a userspace process is controlling the PWM via sysfs.

I agree with you about the sysfs case Tim, but since this is the probe function and not a sysfs callback, should we not leave it as the default value?

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#162 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 7 lines · Jonathan Richardson

Hi Tim,

I'm going to take over this submission because I made the changes to the driver. Arun was filling in for me while I was on leave. Now I'm back and I think I can help clarify why these changes were made. A summary for all the changes should help.

Quoted 5 lines

There were two problems. First was a problem caused by setting the polarity in probe. It caused the speaker to click when the polarity was set so we took that out as it didn't seem to serve any useful purpose that I could see. The polarity changes should be made in the polarity callback.

Please provide more details about your configuration.

Are you using the pwm-beeper driver with a piezo?

After a reset, all PWM output will be low until the PWM clock is enabled at which point it will be constant high. Are you confident that this transition is not responsible for the click you are hearing?

Quoted 4 lines

The second and bigger problem was the smooth type sequence. If it isn't done according to the spec then one in ten or twenty times you won't even get a signal when it's enabled. Following the correct sequence with the 400 ns delays solves this problem.

Would the following minor change be sufficient to fix the issue?

drivers/pwm/pwm-bcm-kona.c +2 -0
index 02bc048..c537efd 100644
@@ -85,6 +85,9 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, uns
        value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
        writel(value, kp->base + PWM_CONTROL_OFFSET);
 
+       ndelay(400);
+
        /* Set trigger bit and clear smooth bit to apply new settings */
        value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
        value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
Quoted 5 lines

Additionally, by not following the sequence you won't get a smooth transition. You'll get a change in the settings (duty cycle, period) but may get a non smooth transition. So it's important to follow the spec here. We don't want non-smooth transitions.

Please provide your rationale for requiring smooth transitions.

Thanks,
Tim Kryger

#163 lore raw

Re: [PATCH v2 1/4] pwm: kona: Remove setting default smooth type and polarity for all channels

Quoted 15 lines · Tim Kryger
Quoted 7 lines · Jonathan Richardson

Hi Tim,

I'm going to take over this submission because I made the changes to the driver. Arun was filling in for me while I was on leave. Now I'm back and I think I can help clarify why these changes were made. A summary for all the changes should help.

Quoted 5 lines

There were two problems. First was a problem caused by setting the polarity in probe. It caused the speaker to click when the polarity was set so we took that out as it didn't seem to serve any useful purpose that I could see. The polarity changes should be made in the polarity callback.

Quoted 3 lines

Please provide more details about your configuration.

Are you using the pwm-beeper driver with a piezo?

Probably, but I don't know. We don't care about it and aren't using it which underscores why we don't want to initialize pwm channels we aren't using.

Quoted 11 lines

After a reset, all PWM output will be low until the PWM clock is enabled at which point it will be constant high. Are you confident that this transition is not responsible for the click you are hearing?

Quoted 4 lines

The second and bigger problem was the smooth type sequence. If it isn't done according to the spec then one in ten or twenty times you won't even get a signal when it's enabled. Following the correct sequence with the 400 ns delays solves this problem.

Would the following minor change be sufficient to fix the issue?

Not quite but hopefully I can send a patch soon for your review.

Quoted 16 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
index 02bc048..c537efd 100644
@@ -85,6 +85,9 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, uns
        value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
        writel(value, kp->base + PWM_CONTROL_OFFSET);
 
+       ndelay(400);
+
        /* Set trigger bit and clear smooth bit to apply new settings */
        value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
        value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
Quoted 2 lines
Quoted 6 lines
Quoted 4 lines

Additionally, by not following the sequence you won't get a smooth transition. You'll get a change in the settings (duty cycle, period) but may get a non smooth transition. So it's important to follow the spec here. We don't want non-smooth transitions.

Please provide your rationale for requiring smooth transitions.

The rationale is we don't want to give customers a bad experience when we can provide them with a better one. The driver attempts to use smooth transitions already but due to the quirks in the procedure which were sent out previously it doesn't quite work as intended. When changing the waveform we want to always have smooth transitions. There are unused pwm channels that vendors can hook up whatever they want.

Thanks,
Jon

Quoted 9 lines

Thanks,
Tim Kryger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

author maintainer
#164 lore raw

PATCH v2 2/4 pwm: kona: Fix incorrect enable after channel polarity change

In reply to Scott Branden

From: Arun Ramamurthy <[email protected]>

The pwm core code requires a separate call for enabling the channel and hence the driver does not need to set pwm_trigger after a polarity change

---
 drivers/pwm/pwm-bcm-kona.c | 5 -----
 1 file changed, 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -5
index 29eef9e..fa0b5bf 100644
@@ -173,11 +173,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-	kona_pwmc_apply_settings(kp, chan);
-
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
-
 	clk_disable_unprepare(kp->clk);
 
 	return 0;
Signature · 1 line
2.1.3
#165 lore raw

Re: [PATCH v2 2/4] pwm: kona: Fix incorrect enable after channel polarity change

Quoted 5 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The pwm core code requires a separate call for enabling the channel and hence the driver does not need to set pwm_trigger after a polarity change

The framework does restrict when polarity changes can occur but it isn't clear to me that there is any reason to delay applying the polarity change. Keep in mind that polarity matters even when a PWM is disabled. While disabled, the output should be equivalent to an enabled configuration with zero duty. Thus for normal polarity the output is constant low and for inversed polarity the output is constant high. I believe there is an expectation that the output is updated to reflect the requested polarity change prior to returning to the caller.

Quoted 27 lines
---
 drivers/pwm/pwm-bcm-kona.c | 5 -----
 1 file changed, 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -6
index 29eef9e..fa0b5bf 100644
@@ -173,11 +173,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
        writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
-
        clk_disable_unprepare(kp->clk);
 
        return 0;
--

2.1.3

#166 lore raw

Re: [PATCH v2 2/4] pwm: kona: Fix incorrect enable after channel polarity change

Quoted 10 lines · Tim Kryger
Quoted 5 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The pwm core code requires a separate call for enabling the channel and hence the driver does not need to set pwm_trigger after a polarity change

The framework does restrict when polarity changes can occur but it isn't clear to me that there is any reason to delay applying the polarity change.

I examined several other drivers such as pwm-atmel-tcb.c, pwm-ep93xx.c, pwm-renesas-tpu.c, pwm-samsung.c in the 3.17 kernel tree and none of them enable the channel after changing polarity. We would be the first driver to do so.

Quoted 5 lines

Keep in mind that polarity matters even when a PWM
is disabled. While disabled, the output should be equivalent to an enabled configuration with zero duty. Thus for normal polarity the output is constant low and for inversed polarity the output is constant high.

The driver does set the duty cycle to zero when disabling the pwm channel.However since the frame work prevents polarity change when the pwm is enabled, I don’t see how one could expect the polarity change to be reflected immediately without a separate call to pwm enable.

I believe there is an expectation that the output is

Quoted 2 lines

updated to reflect the requested polarity change prior to returning to the caller.

Once again I disagree with this based on other pwm drivers which only change the polarity and do not enable the channel when their set polarity functions are called.

Quoted 28 lines
Quoted 28 lines
---
  drivers/pwm/pwm-bcm-kona.c | 5 -----
  1 file changed, 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -6
index 29eef9e..fa0b5bf 100644
@@ -173,11 +173,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
         writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
-
         clk_disable_unprepare(kp->clk);
 
         return 0;
--

2.1.3

#167 lore raw

Re: [PATCH v2 2/4] pwm: kona: Fix incorrect enable after channel polarity change

Quoted 14 lines · Arun Ramamurthy
Quoted 11 lines · Tim Kryger
Quoted 6 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The pwm core code requires a separate call for enabling the channel and hence the driver does not need to set pwm_trigger after a polarity change

Quoted 8 lines
Quoted 3 lines

The framework does restrict when polarity changes can occur but it isn't clear to me that there is any reason to delay applying the polarity change.

I examined several other drivers such as pwm-atmel-tcb.c, pwm-ep93xx.c, pwm-renesas-tpu.c, pwm-samsung.c in the 3.17 kernel tree and none of them enable the channel after changing polarity. We would be the first driver to do so.

We are not "enabling" the channel as much as we are "triggering an application of settings" by hardware.

Both pwm-ep93xx and pwm-samsung write polarity settings to the hardware immediately, presumably resulting in an immediate change in output.

Alternatively, the pwm-atmel-tcb and pwm-renesas-tpu drivers save the polarity and write it to hardware later.

There may be advantages to deferring the application of the polarity till a subsequent enable but both approaches appear to be acceptable.

Quoted 13 lines
Quoted 6 lines

Keep in mind that polarity matters even when a PWM
is disabled. While disabled, the output should be equivalent to an enabled configuration with zero duty. Thus for normal polarity the output is constant low and for inversed polarity the output is constant high.

The driver does set the duty cycle to zero when disabling the pwm channel.However since the frame work prevents polarity change when the pwm is enabled, I don’t see how one could expect the polarity change to be reflected immediately without a separate call to pwm enable.

Quoted 8 lines
Quoted 3 lines

I believe there is an expectation that the output is updated to reflect the requested polarity change prior to returning to the caller.

Once again I disagree with this based on other pwm drivers which only change the polarity and do not enable the channel when their set polarity functions are called.

I don't know why you keep calling this an enable. Its not an enable, it is only a trigger.

Perhaps this would be best explained with an example:

# Export PWM for access by userspace
cd /sys/class/pwm/pwmchip0
echo 0 > export
cd pwm0

# Request 50% duty output when PWM is enabled
echo 50000 > duty_cycle
echo 100000 > period

# Command Inversed Polarity
echo inversed > polarity

# Command Normal Polarity
echo normal > polarity

# Enable PWM
echo 1 > enable

The polarity changes trigger immediate output updates but the PWM is not enabled until the end.

Prior to the last step the output is either a constant high or low signal, not the 50% duty waveform.

Quoted 32 lines
Quoted 31 lines
Quoted 31 lines
---
  drivers/pwm/pwm-bcm-kona.c | 5 -----
  1 file changed, 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -5
index 29eef9e..fa0b5bf 100644
@@ -173,11 +173,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip
 *chip, struct pwm_device *pwm,
 
         writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
-
         clk_disable_unprepare(kp->clk);
 
         return 0;

--
2.1.3

#168 lore raw

Re: [PATCH v2 2/4] pwm: kona: Fix incorrect enable after channel polarity change

Comments below.

Quoted 80 lines · Tim Kryger
Quoted 14 lines · Arun Ramamurthy
Quoted 11 lines · Tim Kryger
Quoted 6 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

The pwm core code requires a separate call for enabling the channel and hence the driver does not need to set pwm_trigger after a polarity change

Quoted 8 lines
Quoted 3 lines

The framework does restrict when polarity changes can occur but it isn't clear to me that there is any reason to delay applying the polarity change.

I examined several other drivers such as pwm-atmel-tcb.c, pwm-ep93xx.c, pwm-renesas-tpu.c, pwm-samsung.c in the 3.17 kernel tree and none of them enable the channel after changing polarity. We would be the first driver to do so.

We are not "enabling" the channel as much as we are "triggering an application of settings" by hardware.

Both pwm-ep93xx and pwm-samsung write polarity settings to the hardware immediately, presumably resulting in an immediate change in output.

Alternatively, the pwm-atmel-tcb and pwm-renesas-tpu drivers save the polarity and write it to hardware later.

There may be advantages to deferring the application of the polarity till a subsequent enable but both approaches appear to be acceptable.

Quoted 13 lines
Quoted 6 lines

Keep in mind that polarity matters even when a PWM
is disabled. While disabled, the output should be equivalent to an enabled configuration with zero duty. Thus for normal polarity the output is constant low and for inversed polarity the output is constant high.

The driver does set the duty cycle to zero when disabling the pwm channel.However since the frame work prevents polarity change when the pwm is enabled, I don’t see how one could expect the polarity change to be reflected immediately without a separate call to pwm enable.

Quoted 8 lines
Quoted 3 lines

I believe there is an expectation that the output is updated to reflect the requested polarity change prior to returning to the caller.

Once again I disagree with this based on other pwm drivers which only change the polarity and do not enable the channel when their set polarity functions are called.

I don't know why you keep calling this an enable. Its not an enable, it is only a trigger.

Perhaps this would be best explained with an example:

# Export PWM for access by userspace
cd /sys/class/pwm/pwmchip0
echo 0 > export
cd pwm0

# Request 50% duty output when PWM is enabled
echo 50000 > duty_cycle
echo 100000 > period

# Command Inversed Polarity
echo inversed > polarity

# Command Normal Polarity
echo normal > polarity

Quoted 9 lines

# Enable PWM
echo 1 > enable

The polarity changes trigger immediate output updates but the PWM is not enabled until the end.

Prior to the last step the output is either a constant high or low signal, not the 50% duty waveform.

I just want to clarify so we're on the same page here. The pwm channel needs to be disabled when polarity is set. When the set polarity callback is called it just needs to update the polarity so that when the channel is enabled again the new polarity value is used. We write this to the polarity register in the callback which seems appropriate. Also note that the clock is disabled at the end of the routine so the signal is just going to be floating anyway. Hopefully this makes sense.

Quoted 38 lines
Quoted 27 lines
Quoted 27 lines
Quoted 27 lines
---
  drivers/pwm/pwm-bcm-kona.c | 5 -----
  1 file changed, 5 deletions(-)
drivers/pwm/pwm-bcm-kona.c +0 -5
index 29eef9e..fa0b5bf 100644
@@ -173,11 +173,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip
 *chip, struct pwm_device *pwm,
 
         writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
-
         clk_disable_unprepare(kp->clk);
 
Quoted 5 lines
Quoted 4 lines
Quoted 4 lines
         return 0;

--
2.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

author maintainer
#169 lore raw

PATCH v2 3/4 pwm: kona: Fix enable, disable and config procedures

In reply to Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

---
 drivers/pwm/pwm-bcm-kona.c | 100 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 78 insertions(+), 22 deletions(-)
drivers/pwm/pwm-bcm-kona.c +78 -22
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
 #define DUTY_CYCLE_HIGH_MIN			(0x00000000)
 #define DUTY_CYCLE_HIGH_MAX			(0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
 struct kona_pwmc {
 	struct pwm_chip chip;
 	void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
 	return container_of(_chip, struct kona_pwmc, chip);
 }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+					 unsigned int chan)
 {
 	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-	/* Clear trigger bit but set smooth bit to maintain old output */
-	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	/* set trigger bit to enable channel */
+	value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
+	ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+					   unsigned int chan)
+{
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/* Clear trigger bit */
 	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
+	ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-	/* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+					  unsigned int chan)
+{
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/* Clear smooth bit */
 	value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-	value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned int chan)
+{
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/*  set smooth bit to maintain old output */
+	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int chan,
+				     unsigned long prescale, unsigned long pc,
+				     unsigned long dc)
+{
+	unsigned int value;
+
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	value |= prescale << PRESCALE_SHIFT(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+	writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			    int duty_ns, int period_ns)
 {
 	struct kona_pwmc *kp = to_kona_pwmc(chip);
 	u64 val, div, rate;
 	unsigned long prescale = PRESCALE_MIN, pc, dc;
-	unsigned int value, chan = pwm->hwpwm;
+	unsigned int ret, chan = pwm->hwpwm;
 
 	/*
 	 * Find period count, duty count and prescale to suit duty_ns and
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			return -EINVAL;
 	}
 
-	/* If the PWM channel is enabled, write the settings to the HW */
-	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-		value = readl(kp->base + PRESCALE_OFFSET);
-		value &= ~PRESCALE_MASK(chan);
-		value |= prescale << PRESCALE_SHIFT(chan);
-		writel(value, kp->base + PRESCALE_OFFSET);
 
-		writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+	/* If the PWM channel is not enabled, enable the clock */
+	if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+		ret = clk_prepare_enable(kp->clk);
+		if (ret < 0) {
+			dev_err(chip->dev, "failed to enable clock: %d\n", ret);
+			return ret;
+		}
+	}
 
-		writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+	/* Set smooth bit to maintain old output */
+	kona_pwmc_set_smooth(kp, chan);
+	kona_pwmc_clear_trigger(kp, chan);
+
+	/* apply new settings */
+	kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+	/*If the PWM is enabled, enable the channel with the new settings
+	 and if not  disable the clock*/
+	if (test_bit(PWMF_ENABLED, &pwm->flags))
+		kona_pwmc_set_trigger(kp, chan);
+	else
+		clk_disable_unprepare(kp->clk);
 
-		kona_pwmc_apply_settings(kp, chan);
-	}
 
 	return 0;
 }
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 		dev_err(chip->dev, "failed to enable clock: %d\n", ret);
 		return ret;
 	}
-
 	ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
 	if (ret < 0) {
 		clk_disable_unprepare(kp->clk);
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	struct kona_pwmc *kp = to_kona_pwmc(chip);
 	unsigned int chan = pwm->hwpwm;
 
+	kona_pwmc_clear_smooth(kp, chan);
+	kona_pwmc_clear_trigger(kp, chan);
 	/* Simulate a disable by configuring for zero duty */
-	writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-	kona_pwmc_apply_settings(kp, chan);
-
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
+	kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+	kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);
+	kona_pwmc_set_trigger(kp, chan);
 
 	clk_disable_unprepare(kp->clk);
 }
Signature · 1 line
2.1.3
#170 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 6 lines
---
 drivers/pwm/pwm-bcm-kona.c | 100 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 78 insertions(+), 22 deletions(-)

The driver is fairly small and this change rewrites a considerable amount of it.

Is there a actually specific deficiency that this change is intended to address?

I'm not sure all the extra helper functions improve readability.

Quoted 143 lines
drivers/pwm/pwm-bcm-kona.c +73 -17
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
 #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
 #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
 struct kona_pwmc {
        struct pwm_chip chip;
        void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
        return container_of(_chip, struct kona_pwmc, chip);
 }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
 {
        unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
        value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
        writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
        value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
        writel(value, kp->base + PWM_CONTROL_OFFSET);
 }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int chan,
+                                    unsigned long prescale, unsigned long pc,
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                            int duty_ns, int period_ns)
 {
        struct kona_pwmc *kp = to_kona_pwmc(chip);
        u64 val, div, rate;
        unsigned long prescale = PRESCALE_MIN, pc, dc;
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
        /*
         * Find period count, duty count and prescale to suit duty_ns and
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                        return -EINVAL;
        }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock: %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new settings
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
        return 0;
 }
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
                dev_err(chip->dev, "failed to enable clock: %d\n", ret);
                return ret;
        }
-
        ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
        if (ret < 0) {
                clk_disable_unprepare(kp->clk);

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 5 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        struct kona_pwmc *kp = to_kona_pwmc(chip);
        unsigned int chan = pwm->hwpwm;
 
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 8 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
        /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);

This is wrong. You shouldn't change the polarity when the PWM is disabled.

The original polarity isn't even restored when it is re-enabled...

Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -1
+       kona_pwmc_set_trigger(kp, chan);
 
        clk_disable_unprepare(kp->clk);
 }
--

2.1.3

author maintainer
#171 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

Hi Tim,

Thanks for all your comments on the patchset. We are in the process of reviewing and will provide feedback when that is completed.

Scott

Quoted 195 lines · Tim Kryger
Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 6 lines
---
  drivers/pwm/pwm-bcm-kona.c | 100 +++++++++++++++++++++++++++++++++++----------
  1 file changed, 78 insertions(+), 22 deletions(-)

The driver is fairly small and this change rewrites a considerable amount of it.

Is there a actually specific deficiency that this change is intended to address?

I'm not sure all the extra helper functions improve readability.

Quoted 143 lines
drivers/pwm/pwm-bcm-kona.c +73 -17
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
  #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
  #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
  struct kona_pwmc {
         struct pwm_chip chip;
         void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
         return container_of(_chip, struct kona_pwmc, chip);
  }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
  {
         unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
         value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
         writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
         value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
         writel(value, kp->base + PWM_CONTROL_OFFSET);
  }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int chan,
+                                    unsigned long prescale, unsigned long pc,
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
  static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                             int duty_ns, int period_ns)
  {
         struct kona_pwmc *kp = to_kona_pwmc(chip);
         u64 val, div, rate;
         unsigned long prescale = PRESCALE_MIN, pc, dc;
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
         /*
          * Find period count, duty count and prescale to suit duty_ns and
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                         return -EINVAL;
         }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock: %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new settings
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
         return 0;
  }
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
                 dev_err(chip->dev, "failed to enable clock: %d\n", ret);
                 return ret;
         }
-
         ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
         if (ret < 0) {
                 clk_disable_unprepare(kp->clk);

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 5 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
         struct kona_pwmc *kp = to_kona_pwmc(chip);
         unsigned int chan = pwm->hwpwm;
 
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 8 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
         /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);

This is wrong. You shouldn't change the polarity when the PWM is disabled.

The original polarity isn't even restored when it is re-enabled...

Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -1
+       kona_pwmc_set_trigger(kp, chan);
 
         clk_disable_unprepare(kp->clk);
  }
--

2.1.3

#172 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

In reply to Tim Kryger
Quoted 18 lines · Tim Kryger
Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 6 lines
---
  drivers/pwm/pwm-bcm-kona.c | 100 +++++++++++++++++++++++++++++++++++----------
  1 file changed, 78 insertions(+), 22 deletions(-)
Quoted 4 lines

The driver is fairly small and this change rewrites a considerable amount of it.

Is there a actually specific deficiency that this change is intended to address?

The main issue this patchset addresses is setting the period and duty cycle when the pwm is disabled. This is done by turning on the clock and writing to the PWM registers. Additionally it also adds the 400ns
delays specified by the PWM spec when setting or clearing certain bits. It also updates the PWM programming procedure to match the spec more closely. Although there is considerable change, all of it addresses the core functionality and it would not make sense to split it into multiple patches.

Quoted 2 lines

I'm not sure all the extra helper functions improve readability.

There was a lot of repeated code in various different functions. It seemed more efficient to consolidate them into helper functions. It also helped when comparing the spec to the code to check if we were setting the bits in the right order.

Quoted 146 lines
Quoted 146 lines
drivers/pwm/pwm-bcm-kona.c +73 -17
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
  #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
  #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
  struct kona_pwmc {
         struct pwm_chip chip;
         void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
         return container_of(_chip, struct kona_pwmc, chip);
  }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
  {
         unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
         value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
         writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
         value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
         writel(value, kp->base + PWM_CONTROL_OFFSET);
  }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int chan,
+                                    unsigned long prescale, unsigned long pc,
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
  static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                             int duty_ns, int period_ns)
  {
         struct kona_pwmc *kp = to_kona_pwmc(chip);
         u64 val, div, rate;
         unsigned long prescale = PRESCALE_MIN, pc, dc;
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
         /*
          * Find period count, duty count and prescale to suit duty_ns and
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                         return -EINVAL;
         }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock: %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new settings
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
         return 0;
  }
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
                 dev_err(chip->dev, "failed to enable clock: %d\n", ret);
                 return ret;
         }
-
         ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
         if (ret < 0) {
                 clk_disable_unprepare(kp->clk);
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
         struct kona_pwmc *kp = to_kona_pwmc(chip);
         unsigned int chan = pwm->hwpwm;
 
Quoted 4 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 2 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

According to spec, this is the procedure to program the PWM and the code follows that:

STEP0: Program SMOOTH_TYPE=1. That will only allow changing of PWM setting at the PWM period boundary.
STEP1: Program PWMOUT_ENABLE=0. At this time, PWM internal logic will
continue to run with the previous settings. (i.e. If PWM is at 50Hz 40% duty cycle before, during the time when PWMOUT_ENABLE=0, it will still run at 50MHz 40% duty cycle.)
STEP2: Program PWM register for new setting (i.e. PRESCALE, DUTY,
PERIOD etc)
STEP3: Program PWMOUT_ENABLE=1. That will load the new PWM setting
from APB into PWM internal register. (Note. Minimum of 400ns is needed between step1 and step3. )
STEP4: Keep PWMOUT ENABLE=1. (Note: If user didn't hold
PWMOUT_ENABLE=1 for longer than 400ns, PWM internal logic will discard the new PWM setting in step2. User should hold the PWMOUT_ENABLE=1 unless new PWM settings is needed.)

Quoted 10 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 9 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
         /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);
Quoted 4 lines

This is wrong. You shouldn't change the polarity when the PWM is disabled.

The original polarity isn't even restored when it is re-enabled...

this is procedure from the PWM spec to disable :

STEP0: Program SMOOTH_TYPE=0.
STEP1: Program PWMOUT_ENABLE=0. Now, PWM internal logic will be at
reset, PWM output will be default at 1.
STEP2: Program PWM register to these setting. PRESCALE=0, POLARITY=1,
DUTY=0, PERIOD=0.
STEP3: Program PWMOUT_ENABLE=1, and Keep SMOOTH_TYPE=0.
STEP4: Turn off PWM clock from CCU, and Keep PWMOUT ENABLE=1. (Note,
It takes 400ns from STEP3 to turn off the LCD backlight, and user should guarantee that the PWM clock will not be disabled in less than 400ns after STEP3.

I agree with you that the original polarity isnt restored. I will need to add some code to check the syfs polarity value when the PWM is enabled. However, if i was to comply with the above spec, I would still have set the polarity. I just realized it should be set to inverted and I will fix this in the next patchset

Quoted 7 lines
Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -1
+       kona_pwmc_set_trigger(kp, chan);
 
         clk_disable_unprepare(kp->clk);
  }
--

2.1.3

#173 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

Quoted 32 lines · Arun Ramamurthy
Quoted 23 lines · Tim Kryger
Quoted 11 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 7 lines
---
  drivers/pwm/pwm-bcm-kona.c | 100
+++++++++++++++++++++++++++++++++++----------
  1 file changed, 78 insertions(+), 22 deletions(-)
Quoted 6 lines

The driver is fairly small and this change rewrites a considerable amount of it.

Is there a actually specific deficiency that this change is intended to address?

Quoted 7 lines

The main issue this patchset addresses is setting the period and duty cycle when the pwm is disabled. This is done by turning on the clock and writing to the PWM registers. Additionally it also adds the 400ns
delays specified by the PWM spec when setting or clearing certain bits. It also updates the PWM programming procedure to match the spec more closely. Although there is considerable change, all of it addresses the core functionality and it would not make sense to split it into multiple patches.

So what you are saying is that there isn't any known issue that this resolves.

This only changes the driver to use an alternate programming sequence?

The benefit here seems uncertain.

Quoted 208 lines
Quoted 3 lines

I'm not sure all the extra helper functions improve readability.

There was a lot of repeated code in various different functions. It seemed more efficient to consolidate them into helper functions. It also helped when comparing the spec to the code to check if we were setting the bits in the right order.

Quoted 157 lines
Quoted 157 lines
drivers/pwm/pwm-bcm-kona.c +51 -5
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
  #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
  #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
  struct kona_pwmc {
         struct pwm_chip chip;
         void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct
 pwm_chip *_chip)
         return container_of(_chip, struct kona_pwmc, chip);
  }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int
 chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
  {
         unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
         value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
         writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
         value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
         writel(value, kp->base + PWM_CONTROL_OFFSET);
  }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned
 int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int
 chan,
+                                    unsigned long prescale, unsigned
 long pc,
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
  static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device
 *pwm,
                             int duty_ns, int period_ns)
  {
         struct kona_pwmc *kp = to_kona_pwmc(chip);
         u64 val, div, rate;
         unsigned long prescale = PRESCALE_MIN, pc, dc;
drivers/pwm/pwm-bcm-kona.c +1 -1
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
         /*
          * Find period count, duty count and prescale to suit duty_ns

and

drivers/pwm/pwm-bcm-kona.c +21 -10
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip,
 struct pwm_device *pwm,
                         return -EINVAL;
         }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock:
 %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new settings
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
         return 0;

}

drivers/pwm/pwm-bcm-kona.c +0 -1
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip,
 struct pwm_device *pwm)
                 dev_err(chip->dev, "failed to enable clock: %d\n", ret);
                 return ret;
         }
-
         ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
         if (ret < 0) {
                 clk_disable_unprepare(kp->clk);
drivers/pwm/pwm-bcm-kona.c +0 -0
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip
 *chip, struct pwm_device *pwm)
         struct kona_pwmc *kp = to_kona_pwmc(chip);
         unsigned int chan = pwm->hwpwm;
 
Quoted 5 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 2 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

According to spec, this is the procedure to program the PWM and the code follows that:

STEP0: Program SMOOTH_TYPE=1. That will only allow changing of PWM setting at the PWM period boundary.
STEP1: Program PWMOUT_ENABLE=0. At this time, PWM internal logic will
continue to run with the previous settings. (i.e. If PWM is at 50Hz 40% duty cycle before, during the time when PWMOUT_ENABLE=0, it will still run at 50MHz 40% duty cycle.)
STEP2: Program PWM register for new setting (i.e. PRESCALE, DUTY, PERIOD
etc)
STEP3: Program PWMOUT_ENABLE=1. That will load the new PWM setting from APB
into PWM internal register. (Note. Minimum of 400ns is needed between step1 and step3. )
STEP4: Keep PWMOUT ENABLE=1. (Note: If user didn't hold PWMOUT_ENABLE=1 for
longer than 400ns, PWM internal logic will discard the new PWM setting in step2. User should hold the PWMOUT_ENABLE=1 unless new PWM settings is needed.)

Quoted 14 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 9 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
         /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);

This is wrong. You shouldn't change the polarity when the PWM is disabled.

Quoted 7 lines
Quoted 2 lines

The original polarity isn't even restored when it is re-enabled...

this is procedure from the PWM spec to disable :

STEP0: Program SMOOTH_TYPE=0.
STEP1: Program PWMOUT_ENABLE=0. Now, PWM internal logic will be at reset,
PWM output will be default at 1.

This is exactly what I was saying before. You glitch the output high for no good reason.

The sequence in the document isn't gospel. From what I recall, it was just a verification engineer's best guess at how to get a very unusual PWM controller to do the normal PWM things.

Quoted 23 lines

STEP2: Program PWM register to these setting. PRESCALE=0, POLARITY=1,
DUTY=0, PERIOD=0.
STEP3: Program PWMOUT_ENABLE=1, and Keep SMOOTH_TYPE=0.
STEP4: Turn off PWM clock from CCU, and Keep PWMOUT ENABLE=1. (Note, It
takes 400ns from STEP3 to turn off the LCD backlight, and user should guarantee that the PWM clock will not be disabled in less than 400ns after STEP3.

I agree with you that the original polarity isnt restored. I will need to add some code to check the syfs polarity value when the PWM is enabled. However, if i was to comply with the above spec, I would still have set the polarity. I just realized it should be set to inverted and I will fix this in the next patchset

Quoted 7 lines
Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -0
+       kona_pwmc_set_trigger(kp, chan);
 
         clk_disable_unprepare(kp->clk);

}
--
2.1.3

#174 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

Quoted 42 lines · Tim Kryger
Quoted 32 lines · Arun Ramamurthy
Quoted 23 lines · Tim Kryger
Quoted 11 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 7 lines
---
   drivers/pwm/pwm-bcm-kona.c | 100
+++++++++++++++++++++++++++++++++++----------
   1 file changed, 78 insertions(+), 22 deletions(-)
Quoted 6 lines

The driver is fairly small and this change rewrites a considerable amount of it.

Is there a actually specific deficiency that this change is intended to address?

Quoted 7 lines

The main issue this patchset addresses is setting the period and duty cycle when the pwm is disabled. This is done by turning on the clock and writing to the PWM registers. Additionally it also adds the 400ns
delays specified by the PWM spec when setting or clearing certain bits. It also updates the PWM programming procedure to match the spec more closely. Although there is considerable change, all of it addresses the core functionality and it would not make sense to split it into multiple patches.

Quoted 6 lines

So what you are saying is that there isn't any known issue that this resolves.

This only changes the driver to use an alternate programming sequence?

The benefit here seems uncertain.

Actually Tim, it addresses the bug where period and duty cycle are not set if the PWM channel is not enabled in sysfs. Following up on your example you provided in your other email:

# Disable PWM
echo 0 > enable

# Change to a 25% duty output when PWM is enabled
echo 25000 > duty_cycle

The original code would not write this duty cycle change to the registers as the PWmF_ENABLED bit is not set and the clocks are turned off.

I can remove all the helper functions and address only this particular bug if you prefer that.

Quoted 216 lines
Quoted 208 lines
Quoted 3 lines

I'm not sure all the extra helper functions improve readability.

There was a lot of repeated code in various different functions. It seemed more efficient to consolidate them into helper functions. It also helped when comparing the spec to the code to check if we were setting the bits in the right order.

Quoted 157 lines
Quoted 157 lines
drivers/pwm/pwm-bcm-kona.c +51 -5
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
   #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
   #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
   struct kona_pwmc {
          struct pwm_chip chip;
          void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct
 pwm_chip *_chip)
          return container_of(_chip, struct kona_pwmc, chip);
   }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int
 chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
   {
          unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
          value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
          writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
          value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
          writel(value, kp->base + PWM_CONTROL_OFFSET);
   }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned
 int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int
 chan,
+                                    unsigned long prescale, unsigned
 long pc,
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
   static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device
 *pwm,
                              int duty_ns, int period_ns)
   {
          struct kona_pwmc *kp = to_kona_pwmc(chip);
          u64 val, div, rate;
          unsigned long prescale = PRESCALE_MIN, pc, dc;
drivers/pwm/pwm-bcm-kona.c +1 -1
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
          /*
           * Find period count, duty count and prescale to suit duty_ns

and

drivers/pwm/pwm-bcm-kona.c +21 -10
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip,
 struct pwm_device *pwm,
                          return -EINVAL;
          }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock:
 %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new settings
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
          return 0;

}

drivers/pwm/pwm-bcm-kona.c +0 -1
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip,
 struct pwm_device *pwm)
                  dev_err(chip->dev, "failed to enable clock: %d\n", ret);
                  return ret;
          }
-
          ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
          if (ret < 0) {
                  clk_disable_unprepare(kp->clk);
drivers/pwm/pwm-bcm-kona.c +0 -0
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip
 *chip, struct pwm_device *pwm)
          struct kona_pwmc *kp = to_kona_pwmc(chip);
          unsigned int chan = pwm->hwpwm;
 
Quoted 5 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 2 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

According to spec, this is the procedure to program the PWM and the code follows that:

STEP0: Program SMOOTH_TYPE=1. That will only allow changing of PWM setting at the PWM period boundary.
STEP1: Program PWMOUT_ENABLE=0. At this time, PWM internal logic will
continue to run with the previous settings. (i.e. If PWM is at 50Hz 40% duty cycle before, during the time when PWMOUT_ENABLE=0, it will still run at 50MHz 40% duty cycle.)
STEP2: Program PWM register for new setting (i.e. PRESCALE, DUTY, PERIOD
etc)
STEP3: Program PWMOUT_ENABLE=1. That will load the new PWM setting from APB
into PWM internal register. (Note. Minimum of 400ns is needed between step1 and step3. )
STEP4: Keep PWMOUT ENABLE=1. (Note: If user didn't hold PWMOUT_ENABLE=1 for
longer than 400ns, PWM internal logic will discard the new PWM setting in step2. User should hold the PWMOUT_ENABLE=1 unless new PWM settings is needed.)

Quoted 14 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 9 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
          /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);

This is wrong. You shouldn't change the polarity when the PWM is disabled.

Quoted 7 lines
Quoted 2 lines

The original polarity isn't even restored when it is re-enabled...

this is procedure from the PWM spec to disable :

STEP0: Program SMOOTH_TYPE=0.
STEP1: Program PWMOUT_ENABLE=0. Now, PWM internal logic will be at reset,
PWM output will be default at 1.

Quoted 6 lines

This is exactly what I was saying before. You glitch the output high for no good reason.

The sequence in the document isn't gospel. From what I recall, it was just a verification engineer's best guess at how to get a very unusual PWM controller to do the normal PWM things.

So to summarize, you would prefer that the disable procedure be left unchanged which is to set the duty cycle to zero.

Quoted 24 lines
Quoted 24 lines

STEP2: Program PWM register to these setting. PRESCALE=0, POLARITY=1,
DUTY=0, PERIOD=0.
STEP3: Program PWMOUT_ENABLE=1, and Keep SMOOTH_TYPE=0.
STEP4: Turn off PWM clock from CCU, and Keep PWMOUT ENABLE=1. (Note, It
takes 400ns from STEP3 to turn off the LCD backlight, and user should guarantee that the PWM clock will not be disabled in less than 400ns after STEP3.

I agree with you that the original polarity isnt restored. I will need to add some code to check the syfs polarity value when the PWM is enabled. However, if i was to comply with the above spec, I would still have set the polarity. I just realized it should be set to inverted and I will fix this in the next patchset

Quoted 7 lines
Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -0
+       kona_pwmc_set_trigger(kp, chan);
 
          clk_disable_unprepare(kp->clk);
   }

--
2.1.3

#175 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

Quoted 68 lines · Arun Ramamurthy
Quoted 54 lines · Tim Kryger
Quoted 37 lines · Arun Ramamurthy
Quoted 26 lines · Tim Kryger
Quoted 12 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 7 lines
---
   drivers/pwm/pwm-bcm-kona.c | 100
+++++++++++++++++++++++++++++++++++----------
   1 file changed, 78 insertions(+), 22 deletions(-)
Quoted 7 lines

The driver is fairly small and this change rewrites a considerable amount
of it.

Is there a actually specific deficiency that this change is intended to address?

Quoted 12 lines

The main issue this patchset addresses is setting the period and duty cycle
when the pwm is disabled. This is done by turning on the clock and writing
to the PWM registers. Additionally it also adds the 400ns delays specified by the PWM spec when setting or clearing certain bits. It
also updates the PWM programming procedure to match the spec more closely.
Although there is considerable change, all of it addresses the core functionality and it would not make sense to split it into multiple patches.

Quoted 7 lines

So what you are saying is that there isn't any known issue that this resolves.

This only changes the driver to use an alternate programming sequence?

The benefit here seems uncertain.

Actually Tim, it addresses the bug where period and duty cycle are not set if the PWM channel is not enabled in sysfs. Following up on your example you provided in your other email:

Quoted 8 lines

# Disable PWM
echo 0 > enable

# Change to a 25% duty output when PWM is enabled
echo 25000 > duty_cycle

The original code would not write this duty cycle change to the registers as the PWmF_ENABLED bit is not set and the clocks are turned off.

You are mistaken. There is no bug here. This is by design.

A subsequent enable results in the requested duty and period being set.

Quoted 243 lines

I can remove all the helper functions and address only this particular bug if you prefer that.

Quoted 240 lines
Quoted 227 lines
Quoted 3 lines

I'm not sure all the extra helper functions improve readability.

There was a lot of repeated code in various different functions. It seemed
more efficient to consolidate them into helper functions. It also helped when comparing the spec to the code to check if we were setting the bits in the right order.

Quoted 166 lines
Quoted 166 lines
drivers/pwm/pwm-bcm-kona.c +4 -1
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
   #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
   #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
   struct kona_pwmc {
          struct pwm_chip chip;
          void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct
 pwm_chip *_chip)
          return container_of(_chip, struct kona_pwmc, chip);
   }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned

int
chan)

drivers/pwm/pwm-bcm-kona.c +2 -1
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
   {
          unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output

*/

drivers/pwm/pwm-bcm-kona.c +13 -2
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
          value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
          writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings

*/

drivers/pwm/pwm-bcm-kona.c +7 -1
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
          value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
          writel(value, kp->base + PWM_CONTROL_OFFSET);
   }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned

int chan)

drivers/pwm/pwm-bcm-kona.c +9 -0
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned

int
chan,
+ unsigned long prescale, unsigned
long pc,

drivers/pwm/pwm-bcm-kona.c +15 -0
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
   static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device

*pwm,
int duty_ns, int period_ns)

   {
          struct kona_pwmc *kp = to_kona_pwmc(chip);
          u64 val, div, rate;
          unsigned long prescale = PRESCALE_MIN, pc, dc;
drivers/pwm/pwm-bcm-kona.c +1 -1
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
          /*
           * Find period count, duty count and prescale to suit duty_ns

and

drivers/pwm/pwm-bcm-kona.c +16 -8
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip
 *chip,
 struct pwm_device *pwm,
                          return -EINVAL;
          }
 
-       /* If the PWM channel is enabled, write the settings to the HW
 */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock:
 %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new

settings

drivers/pwm/pwm-bcm-kona.c +5 -3
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
          return 0;
   }
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip,
 struct pwm_device *pwm)
                  dev_err(chip->dev, "failed to enable clock: %d\n",
 ret);
                  return ret;
          }
-
          ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle,
pwm->period);
          if (ret < 0) {
                  clk_disable_unprepare(kp->clk);
drivers/pwm/pwm-bcm-kona.c +0 -0
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip
 *chip, struct pwm_device *pwm)
          struct kona_pwmc *kp = to_kona_pwmc(chip);
          unsigned int chan = pwm->hwpwm;
 
Quoted 6 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 2 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

According to spec, this is the procedure to program the PWM and the code follows that:

STEP0: Program SMOOTH_TYPE=1. That will only allow changing of PWM setting
at the PWM period boundary.
STEP1: Program PWMOUT_ENABLE=0. At this time, PWM internal logic will
continue to run with the previous settings. (i.e. If PWM is at 50Hz 40% duty
cycle before, during the time when PWMOUT_ENABLE=0, it will still run at 50MHz 40% duty cycle.)
STEP2: Program PWM register for new setting (i.e. PRESCALE, DUTY,
PERIOD
etc)
STEP3: Program PWMOUT_ENABLE=1. That will load the new PWM setting from
APB
into PWM internal register. (Note. Minimum of 400ns is needed between step1
and step3. )
STEP4: Keep PWMOUT ENABLE=1. (Note: If user didn't hold PWMOUT_ENABLE=1
for
longer than 400ns, PWM internal logic will discard the new PWM setting in step2. User should hold the PWMOUT_ENABLE=1 unless new PWM settings is needed.)

Quoted 15 lines

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 9 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
          /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);

This is wrong. You shouldn't change the polarity when the PWM is disabled.

Quoted 8 lines
Quoted 2 lines

The original polarity isn't even restored when it is re-enabled...

this is procedure from the PWM spec to disable :

STEP0: Program SMOOTH_TYPE=0.
STEP1: Program PWMOUT_ENABLE=0. Now, PWM internal logic will be at
reset,
PWM output will be default at 1.

This is exactly what I was saying before. You glitch the output high for no good reason.

Quoted 7 lines
Quoted 3 lines

The sequence in the document isn't gospel. From what I recall, it was just a verification engineer's best guess at how to get a very unusual PWM controller to do the normal PWM things.

So to summarize, you would prefer that the disable procedure be left unchanged which is to set the duty cycle to zero.

I would be much more likely to give my approval to a patch that identified a specific issue and resolved it without unnecessarily rewriting large parts of the driver.

Quoted 29 lines
Quoted 28 lines
Quoted 28 lines

STEP2: Program PWM register to these setting. PRESCALE=0, POLARITY=1,
DUTY=0, PERIOD=0.
STEP3: Program PWMOUT_ENABLE=1, and Keep SMOOTH_TYPE=0.
STEP4: Turn off PWM clock from CCU, and Keep PWMOUT ENABLE=1. (Note, It
takes 400ns from STEP3 to turn off the LCD backlight, and user should guarantee that the PWM clock will not be disabled in less than 400ns after
STEP3.

I agree with you that the original polarity isnt restored. I will need to add some code to check the syfs polarity value when the PWM is enabled. However, if i was to comply with the above spec, I would still have set the
polarity. I just realized it should be set to inverted and I will fix this
in the next patchset

Quoted 7 lines
Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -0
+       kona_pwmc_set_trigger(kp, chan);
 
          clk_disable_unprepare(kp->clk);
   }

--
2.1.3

#176 lore raw

Re: [PATCH v2 3/4] pwm: kona: Fix enable, disable and config procedures

In reply to Tim Kryger

Hi Tim,

Comments below.

Quoted 18 lines · Tim Kryger
Quoted 10 lines · Scott Branden

From: Arun Ramamurthy <[email protected]>

- Added helper functions to set and clear smooth and trigger bits
- Added 400ns delays when clearing and setting trigger bit as requied by spec
- Added helper function to write prescale and other settings
- Updated config procedure to match spec
- Added code to handle pwn config when channel is disabled
- Updated disable procedure to match spec

Quoted 6 lines
---
 drivers/pwm/pwm-bcm-kona.c | 100 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 78 insertions(+), 22 deletions(-)
Quoted 6 lines

The driver is fairly small and this change rewrites a considerable amount of it.

Is there a actually specific deficiency that this change is intended to address?

I'm not sure all the extra helper functions improve readability.

Hopefully my summary in the previous reply helps clarify. I'm going to remove all the helper functions to make the changes as simple as possible.

Quoted 160 lines
Quoted 143 lines
drivers/pwm/pwm-bcm-kona.c +73 -17
index fa0b5bf..06fa983 100644
@@ -65,6 +65,10 @@
 #define DUTY_CYCLE_HIGH_MIN                    (0x00000000)
 #define DUTY_CYCLE_HIGH_MAX                    (0x00ffffff)
 
+/* The delay required after clearing or setting
+   PWMOUT_ENABLE*/
+#define PWMOUT_ENABLE_HOLD_DELAY 400
+
 struct kona_pwmc {
        struct pwm_chip chip;
        void __iomem *base;
@@ -76,28 +80,70 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
        return container_of(_chip, struct kona_pwmc, chip);
 }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+static inline void kona_pwmc_set_trigger(struct kona_pwmc *kp,
+                                        unsigned int chan)
 {
        unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
-       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       /* set trigger bit to enable channel */
+       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
+static inline void kona_pwmc_clear_trigger(struct kona_pwmc *kp,
+                                          unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear trigger bit */
        value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
        writel(value, kp->base + PWM_CONTROL_OFFSET);
+       ndelay(PWMOUT_ENABLE_HOLD_DELAY);
+}
 
-       /* Set trigger bit and clear smooth bit to apply new settings */
+static inline void kona_pwmc_clear_smooth(struct kona_pwmc *kp,
+                                         unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /* Clear smooth bit */
        value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
-       value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
        writel(value, kp->base + PWM_CONTROL_OFFSET);
 }
 
+static inline void kona_pwmc_set_smooth(struct kona_pwmc *kp, unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+       /*  set smooth bit to maintain old output */
+       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+       writel(value, kp->base + PWM_CONTROL_OFFSET);
+}
+
+static void kona_pwmc_write_settings(struct kona_pwmc *kp, unsigned int chan,
+                                    unsigned long prescale, unsigned long pc,
+                                    unsigned long dc)
+{
+       unsigned int value;
+
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       value |= prescale << PRESCALE_SHIFT(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+}
+
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                            int duty_ns, int period_ns)
 {
        struct kona_pwmc *kp = to_kona_pwmc(chip);
        u64 val, div, rate;
        unsigned long prescale = PRESCALE_MIN, pc, dc;
-       unsigned int value, chan = pwm->hwpwm;
+       unsigned int ret, chan = pwm->hwpwm;
 
        /*
         * Find period count, duty count and prescale to suit duty_ns and
@@ -133,19 +179,30 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                        return -EINVAL;
        }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-               value = readl(kp->base + PRESCALE_OFFSET);
-               value &= ~PRESCALE_MASK(chan);
-               value |= prescale << PRESCALE_SHIFT(chan);
-               writel(value, kp->base + PRESCALE_OFFSET);
 
-               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+       /* If the PWM channel is not enabled, enable the clock */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(kp->clk);
+               if (ret < 0) {
+                       dev_err(chip->dev, "failed to enable clock: %d\n", ret);
+                       return ret;
+               }
+       }
 
-               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+       /* Set smooth bit to maintain old output */
+       kona_pwmc_set_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);
+
+       /* apply new settings */
+       kona_pwmc_write_settings(kp, chan, prescale, pc, dc);
+
+       /*If the PWM is enabled, enable the channel with the new settings
+        and if not  disable the clock*/
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               kona_pwmc_set_trigger(kp, chan);
+       else
+               clk_disable_unprepare(kp->clk);
 
-               kona_pwmc_apply_settings(kp, chan);
-       }
 
        return 0;
 }
@@ -188,7 +245,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
                dev_err(chip->dev, "failed to enable clock: %d\n", ret);
                return ret;
        }
-
        ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
        if (ret < 0) {
                clk_disable_unprepare(kp->clk);

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 263

Quoted 5 lines
drivers/pwm/pwm-bcm-kona.c +2 -0
@@ -203,12 +259,12 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        struct kona_pwmc *kp = to_kona_pwmc(chip);
        unsigned int chan = pwm->hwpwm;
 
+       kona_pwmc_clear_smooth(kp, chan);
+       kona_pwmc_clear_trigger(kp, chan);

I believe the output will spike high here. Likely not what you want...

drivers/pwm/pwm-bcm-kona.c static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) · line 266

Quoted 8 lines
drivers/pwm/pwm-bcm-kona.c +2 -5
        /* Simulate a disable by configuring for zero duty */
-       writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
-
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       kona_pwmc_write_settings(kp, chan, 0, 0, 0);
+       kona_pwmc_set_polarity(chip, pwm, PWM_POLARITY_NORMAL);
Quoted 1 line

This is wrong. You shouldn't change the polarity when the PWM is disabled.

Agreed. No need to set polarity on disable.

Quoted 16 lines

The original polarity isn't even restored when it is re-enabled...

Quoted 7 lines
drivers/pwm/pwm-bcm-kona.c +1 -1
+       kona_pwmc_set_trigger(kp, chan);
 
        clk_disable_unprepare(kp->clk);
 }
--

2.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

author maintainer
#177 lore raw

PATCH v2 4/4 pwm: kona: Update dependency to ARCH_BCM

In reply to Scott Branden

From: Arun Ramamurthy <[email protected]>

change kona driver depends on so to it is available for any Broadcom SoC

---
 drivers/pwm/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pwm/Kconfig +1 -1
index ef2dd2e..186080e 100644
@@ -64,7 +64,7 @@ config PWM_ATMEL_TCB
 
 config PWM_BCM_KONA
 	tristate "Kona PWM support"
-	depends on ARCH_BCM_MOBILE
+	depends on ARCH_BCM
 	help
 	  Generic PWM framework driver for Broadcom Kona PWM block.
 
Signature · 1 line
2.1.3
author maintainer
#178 lore raw

PATCH 1/1 mtd: add reboot notifier to mtdcore and register nand_shutdown with notifier

In reply to a message not in the archive

add (optional) reboot notifier field to struct mtd_info, and use it to register a system reboot notifier on behalf of the lower layers.

Add nand_shutdown to wait for current nand operations to finish and prevent further operations by changing the nand flash state to FL_SHUTDOWN. Register the nand_shutdown with the reboot notifier in nand_base.c

This is addressing a problem observed during reboot tests using UBIFS root file system: NAND erase operations that are in progress during system reboot/shutdown are causing partial erased blocks. Although UBI should be able to detect and recover from this error, this change will avoid the creation of partial erased blocks on reboot in the middle of a NAND erase operation.

---
 drivers/mtd/mtdcore.c        | 20 ++++++++++++++++++++
 drivers/mtd/nand/nand_base.c | 11 +++++++++++
 include/linux/mtd/mtd.h      |  1 +
 3 files changed, 32 insertions(+)
drivers/mtd/mtdcore.c +20 -0
index 4c61187..b80d44f 100644
@@ -37,6 +37,7 @@
 #include <linux/backing-dev.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/reboot.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -365,6 +366,17 @@ static struct device_type mtd_devtype = {
 	.release	= mtd_release,
 };
 
+static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
+			       void *cmd)
+{
+       struct mtd_info *mtd;
+
+       mtd = container_of(n, struct mtd_info, reboot_notifier);
+       mtd->_reboot(mtd);
+
+       return NOTIFY_DONE;
+}
+
 /**
  *	add_mtd_device - register an MTD device
  *	@mtd: pointer to new MTD device info structure
@@ -565,6 +577,11 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 			err = -ENODEV;
 	}
 
+	if (mtd->_reboot) {
+		mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
+		register_reboot_notifier(&mtd->reboot_notifier);
+	}
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(mtd_device_parse_register);
@@ -579,6 +596,9 @@ int mtd_device_unregister(struct mtd_info *master)
 {
 	int err;
 
+	if (master->_reboot)
+		unregister_reboot_notifier(&master->reboot_notifier);
+
 	err = del_mtd_partitions(master);
 	if (err)
 		return err;
drivers/mtd/nand/nand_base.c +11 -0
index 5b5c627..e18165b 100644
@@ -2944,6 +2944,16 @@ static void nand_resume(struct mtd_info *mtd)
 			__func__);
 }
 
+/**
+ * nand_shutdown - [MTD Interface] Finish the current NAND operation and
+ *                 prevent further operations
+ * @mtd: MTD device structure
+ */
+static void nand_shutdown(struct mtd_info *mtd)
+{
+	nand_get_device(mtd, FL_SHUTDOWN);
+}
+
 /* Set default functions */
 static void nand_set_defaults(struct nand_chip *chip, int busw)
 {
@@ -4146,6 +4156,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->_unlock = NULL;
 	mtd->_suspend = nand_suspend;
 	mtd->_resume = nand_resume;
+	mtd->_reboot = nand_shutdown;
 	mtd->_block_isreserved = nand_block_isreserved;
 	mtd->_block_isbad = nand_block_isbad;
 	mtd->_block_markbad = nand_block_markbad;
include/linux/mtd/mtd.h +1 -0
index 031ff3a..c06f537 100644
@@ -227,6 +227,7 @@ struct mtd_info {
 	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
 	int (*_suspend) (struct mtd_info *mtd);
 	void (*_resume) (struct mtd_info *mtd);
+	void (*_reboot) (struct mtd_info *mtd);
 	/*
 	 * If the driver is something smart, like UBI, it may need to maintain
 	 * its own reference counting. The below functions are only for driver.
Signature · 1 line
2.2.0
author maintainer
#179 lore raw

Re: [PATCH] mtd: add reboot notifier to mtdcore and register nand_shutdown with notifier

Apologies: patch fails checkpatch due to spaces instead of tabs during cut and paste.

But, please comment on this patch before I create a new version.

Quoted 117 lines · Scott Branden

add (optional) reboot notifier field to struct mtd_info, and use it to register a system reboot notifier on behalf of the lower layers.

Add nand_shutdown to wait for current nand operations to finish and prevent further operations by changing the nand flash state to FL_SHUTDOWN. Register the nand_shutdown with the reboot notifier in nand_base.c

This is addressing a problem observed during reboot tests using UBIFS root file system: NAND erase operations that are in progress during system reboot/shutdown are causing partial erased blocks. Although UBI should be able to detect and recover from this error, this change will avoid the creation of partial erased blocks on reboot in the middle of a NAND erase operation.

---
  drivers/mtd/mtdcore.c        | 20 ++++++++++++++++++++
  drivers/mtd/nand/nand_base.c | 11 +++++++++++
  include/linux/mtd/mtd.h      |  1 +
  3 files changed, 32 insertions(+)
drivers/mtd/mtdcore.c +20 -0
index 4c61187..b80d44f 100644
@@ -37,6 +37,7 @@
  #include <linux/backing-dev.h>
  #include <linux/gfp.h>
  #include <linux/slab.h>
+#include <linux/reboot.h>
 
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/partitions.h>
@@ -365,6 +366,17 @@ static struct device_type mtd_devtype = {
  	.release	= mtd_release,
  };
 
+static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
+			       void *cmd)
+{
+       struct mtd_info *mtd;
+
+       mtd = container_of(n, struct mtd_info, reboot_notifier);
+       mtd->_reboot(mtd);
+
+       return NOTIFY_DONE;
+}
+
  /**
   *	add_mtd_device - register an MTD device
   *	@mtd: pointer to new MTD device info structure
@@ -565,6 +577,11 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
  			err = -ENODEV;
  	}
 
+	if (mtd->_reboot) {
+		mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
+		register_reboot_notifier(&mtd->reboot_notifier);
+	}
+
  	return err;
  }
  EXPORT_SYMBOL_GPL(mtd_device_parse_register);
@@ -579,6 +596,9 @@ int mtd_device_unregister(struct mtd_info *master)
  {
  	int err;
 
+	if (master->_reboot)
+		unregister_reboot_notifier(&master->reboot_notifier);
+
  	err = del_mtd_partitions(master);
  	if (err)
  		return err;
drivers/mtd/nand/nand_base.c +11 -0
index 5b5c627..e18165b 100644
@@ -2944,6 +2944,16 @@ static void nand_resume(struct mtd_info *mtd)
  			__func__);
  }
 
+/**
+ * nand_shutdown - [MTD Interface] Finish the current NAND operation and
+ *                 prevent further operations
+ * @mtd: MTD device structure
+ */
+static void nand_shutdown(struct mtd_info *mtd)
+{
+	nand_get_device(mtd, FL_SHUTDOWN);
+}
+
  /* Set default functions */
  static void nand_set_defaults(struct nand_chip *chip, int busw)
  {
@@ -4146,6 +4156,7 @@ int nand_scan_tail(struct mtd_info *mtd)
  	mtd->_unlock = NULL;
  	mtd->_suspend = nand_suspend;
  	mtd->_resume = nand_resume;
+	mtd->_reboot = nand_shutdown;
  	mtd->_block_isreserved = nand_block_isreserved;
  	mtd->_block_isbad = nand_block_isbad;
  	mtd->_block_markbad = nand_block_markbad;
include/linux/mtd/mtd.h +1 -0
index 031ff3a..c06f537 100644
@@ -227,6 +227,7 @@ struct mtd_info {
  	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
  	int (*_suspend) (struct mtd_info *mtd);
  	void (*_resume) (struct mtd_info *mtd);
+	void (*_reboot) (struct mtd_info *mtd);
  	/*
  	 * If the driver is something smart, like UBI, it may need to maintain
  	 * its own reference counting. The below functions are only for driver.
#180 lore raw

Re: [PATCH] mtd: add reboot notifier to mtdcore and register nand_shutdown with notifier

Quoted 4 lines · Scott Branden

Apologies: patch fails checkpatch due to spaces instead of tabs during cut and paste.

But, please comment on this patch before I create a new version.

I'd prefer the separation to be as I sent in the first place; one patch to add a generic hook for all MTD's, and one to implement the hook in NAND.

I can just resend my patch (fixed up to compile correctly; I had an error previously), then you can just add your Tested-by.

Brian

author maintainer
#181 lore raw

PATCH 1/1 mmc: sdhci: add quirk for ACMD23 broken

In reply to a message not in the archive

Add quick to handle broken auto-CMD23
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
 drivers/mmc/host/sdhci.c  | 3 ++-
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index ada1a3e..b37331f 100644
@@ -2985,7 +2985,8 @@ int sdhci_add_host(struct sdhci_host *host)
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
 	if ((host->version >= SDHCI_SPEC_300) &&
 	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
 		host->flags |= SDHCI_AUTO_CMD23;
 		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
 	} else {
include/linux/mmc/sdhci.h +2 -0
index dba793e..d979cf9 100644
@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
 /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
 #define SDHCI_QUIRK2_STOP_WITH_TC			(1<<8)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<9)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
Signature · 1 line
2.2.0
author maintainer
#182 lore raw

PATCH v2 1/1 mmc: sdhci: add quirk for ACMD23 broken

In reply to a message not in the archive

Add quirk to handle broken auto-CMD23.
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
 drivers/mmc/host/sdhci.c  | 3 ++-
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index ada1a3e..b37331f 100644
@@ -2985,7 +2985,8 @@ int sdhci_add_host(struct sdhci_host *host)
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
 	if ((host->version >= SDHCI_SPEC_300) &&
 	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
 		host->flags |= SDHCI_AUTO_CMD23;
 		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
 	} else {
include/linux/mmc/sdhci.h +2 -0
index dba793e..d979cf9 100644
@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
 /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
 #define SDHCI_QUIRK2_STOP_WITH_TC			(1<<8)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<9)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
Signature · 1 line
2.2.0
author maintainer
#183 lore raw

Re: [PATCH v2] mmc: sdhci: add quirk for ACMD23 broken

Hi Chris,

I have not received any feedback on this patch for the SDHCI controller.
Anything I can do to help get this accepted into the codebase?

Thanks,
Scott

Quoted 41 lines · Scott Branden

Add quirk to handle broken auto-CMD23.
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
  drivers/mmc/host/sdhci.c  | 3 ++-
  include/linux/mmc/sdhci.h | 2 ++
  2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index ada1a3e..b37331f 100644
@@ -2985,7 +2985,8 @@ int sdhci_add_host(struct sdhci_host *host)
  	/* Auto-CMD23 stuff only works in ADMA or PIO. */
  	if ((host->version >= SDHCI_SPEC_300) &&
  	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
  		host->flags |= SDHCI_AUTO_CMD23;
  		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
  	} else {
include/linux/mmc/sdhci.h +2 -0
index dba793e..d979cf9 100644
@@ -100,6 +100,8 @@ struct sdhci_host {
  #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
  /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
  #define SDHCI_QUIRK2_STOP_WITH_TC			(1<<8)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<9)
 
  	int irq;		/* Device IRQ */
  	void __iomem *ioaddr;	/* Mapped address */
#184 lore raw

Re: [PATCH v2] mmc: sdhci: add quirk for ACMD23 broken

In reply to Scott Branden

Hi Scott, sorry for the delay,

Quoted 32 lines · Scott Branden

Add quirk to handle broken auto-CMD23.
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
 drivers/mmc/host/sdhci.c  | 3 ++-
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index ada1a3e..b37331f 100644
@@ -2985,7 +2985,8 @@ int sdhci_add_host(struct sdhci_host *host)
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
 	if ((host->version >= SDHCI_SPEC_300) &&
 	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
 		host->flags |= SDHCI_AUTO_CMD23;
 		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
 	} else {
include/linux/mmc/sdhci.h +0 -0
index dba793e..d979cf9 100644

include/linux/mmc/sdhci.h struct sdhci_host { · line 107

Quoted 8 lines
include/linux/mmc/sdhci.h +2 -0
@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
 /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
 #define SDHCI_QUIRK2_STOP_WITH_TC			(1<<8)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<9)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */

This patch doesn't apply the quirk to any chipsets, so the patch doesn't actually change any behavior when run on a mainline kernel. Do you have a patch to apply the quirk to your chipset too? We don't typically accept patches that "don't do anything" for mainline users, so that's why we'd like to see the chipset patch too.

Thanks,

- Chris.

Signature · 1 line
Chris Ball   <http://printf.net/>
author maintainer
#185 lore raw

Re: [PATCH v2] mmc: sdhci: add quirk for ACMD23 broken

Hi Chris,

We'll finish off cleaning up our driver that uses this patch for review then.

Thanks,
Scott

Quoted 54 lines · Chris Ball

Hi Scott, sorry for the delay,

Quoted 32 lines · Scott Branden

Add quirk to handle broken auto-CMD23.
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
  drivers/mmc/host/sdhci.c  | 3 ++-
  include/linux/mmc/sdhci.h | 2 ++
  2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index ada1a3e..b37331f 100644
@@ -2985,7 +2985,8 @@ int sdhci_add_host(struct sdhci_host *host)
  	/* Auto-CMD23 stuff only works in ADMA or PIO. */
  	if ((host->version >= SDHCI_SPEC_300) &&
  	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
  		host->flags |= SDHCI_AUTO_CMD23;
  		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
  	} else {
include/linux/mmc/sdhci.h +0 -0
index dba793e..d979cf9 100644

include/linux/mmc/sdhci.h struct sdhci_host { · line 107

Quoted 8 lines
include/linux/mmc/sdhci.h +2 -0
@@ -100,6 +100,8 @@ struct sdhci_host {
  #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
  /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
  #define SDHCI_QUIRK2_STOP_WITH_TC			(1<<8)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<9)
 
  	int irq;		/* Device IRQ */
  	void __iomem *ioaddr;	/* Mapped address */

This patch doesn't apply the quirk to any chipsets, so the patch doesn't actually change any behavior when run on a mainline kernel. Do you have a patch to apply the quirk to your chipset too? We don't typically accept patches that "don't do anything" for mainline users, so that's why we'd like to see the chipset patch too.

Thanks,

- Chris.

author maintainer
#186 lore raw

cover Add support for IPROC SDHCI controller

In reply to a message not in the archive

This series of patchsets contains the IPROC SDHCI driver used in a series of Broadcom SoCs
Quirks are also added to support this controller.

Corneliu Doban (1):
mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

Scott Branden (3):
mmc: sdhci: add quirk for ACMD23 broken
mmc: sdhci-iproc: add IPROC SDHCI driver
mmc: sdhci-iproc: add device tree bindings

 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   |  23 ++
 drivers/mmc/host/Kconfig                           |  14 ++
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/sdhci-iproc.c                     | 241 +++++++++++++++++++++
 drivers/mmc/host/sdhci.c                           |   7 +-
 include/linux/mmc/sdhci.h                          |   2 +
 6 files changed, 286 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
 create mode 100644 drivers/mmc/host/sdhci-iproc.c
Signature · 1 line
2.2.2
author maintainer
#187 lore raw

PATCH 1/4 mmc: sdhci: add quirk for ACMD23 broken

Add quirk to handle broken auto-CMD23.
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
 drivers/mmc/host/sdhci.c  | 3 ++-
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index f1a488e..fcf78ab 100644
@@ -3085,7 +3085,8 @@ int sdhci_add_host(struct sdhci_host *host)
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
 	if ((host->version >= SDHCI_SPEC_300) &&
 	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
 		host->flags |= SDHCI_AUTO_CMD23;
 		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
 	} else {
include/linux/mmc/sdhci.h +2 -0
index f767a0d..a29e9bb 100644
@@ -106,6 +106,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD	(1<<10)
 /* Capability register bit-63 indicates HS400 support */
 #define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400		(1<<11)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<12)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
Signature · 1 line
2.2.2
author maintainer
#188 lore raw

PATCH 2/4 mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

In reply to Scott Branden

From: Corneliu Doban <[email protected]>

For CMD53 in block mode, the host does not need to stop the transfer, as it stops when the block count (present in CMD53) is reached.

---
 drivers/mmc/host/sdhci.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +3 -1
index fcf78ab..f35d413 100644
@@ -28,6 +28,7 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
 #include <linux/mmc/slot-gpio.h>
 
 #include "sdhci.h"
@@ -934,7 +935,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 		 * If we are sending CMD23, CMD12 never gets sent
 		 * on successful completion (so no Auto-CMD12).
 		 */
-		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
+		    (cmd->opcode != SD_IO_RW_EXTENDED))
 			mode |= SDHCI_TRNS_AUTO_CMD12;
 		else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
 			mode |= SDHCI_TRNS_AUTO_CMD23;
Signature · 1 line
2.2.2
author maintainer
#189 lore raw

PATCH 3/4 mmc: sdhci-iproc: add IPROC SDHCI driver

In reply to Scott Branden

Add IPROC SDHCI driver for IPROC family of Broadcom devices.

---
 drivers/mmc/host/Kconfig       |  14 +++
 drivers/mmc/host/Makefile      |   1 +
 drivers/mmc/host/sdhci-iproc.c | 241 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 256 insertions(+)
 create mode 100644 drivers/mmc/host/sdhci-iproc.c
drivers/mmc/host/Kconfig +14 -0
index 2d6fbdd..d6a2ff1 100644
@@ -292,6 +292,20 @@ config MMC_SDHCI_BCM2835
 
 	  If unsure, say N.
 
+config MMC_SDHCI_IPROC
+	tristate "SDHCI platform support for the iProc SD/MMC Controller"
+	depends on ARCH_BCM_IPROC || COMPILE_TEST
+	depends on MMC_SDHCI_PLTFM
+	default ARCH_BCM_IPROC
+	select MMC_SDHCI_IO_ACCESSORS
+	help
+	  This selects the iProc SD/MMC controller.
+
+	  If you have an IPROC platform with SD or MMC devices,
+	  say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_MOXART
 	tristate "MOXART SD/MMC Host Controller support"
 	depends on ARCH_MOXART && MMC
drivers/mmc/host/Makefile +1 -0
index f7b0a77..32f24bd 100644
@@ -70,6 +70,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)	+= sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)		+= sdhci-bcm2835.o
+obj-$(CONFIG_MMC_SDHCI_IPROC)		+= sdhci-iproc.o
 obj-$(CONFIG_MMC_SDHCI_MSM)		+= sdhci-msm.o
 obj-$(CONFIG_MMC_SDHCI_ST)		+= sdhci-st.o
 
drivers/mmc/host/sdhci-iproc.c new file +241 -0

241 lines not on this page · raw message

Signature · 1 line
2.2.2
author maintainer
#190 lore raw

PATCH 4/4 mmc: sdhci-iproc: add device tree bindings

In reply to Scott Branden

Add device tree binding documentation for IPROC SDHCI driver.

---
 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file +23 -0
new file mode 100644
index 0000000..72cc9cc
@@ -0,0 +1,23 @@
+Broadcom IPROC SDHCI controller
+
+This file documents differences between the core properties described
+by mmc.txt and the properties that represent the IPROC SDHCI controller.
+
+Required properties:
+- compatible : Should be "brcm,sdhci-iproc-cygnus".
+- clocks : The clock feeding the SDHCI controller.
+
+Optional properties:
+  - sdhci,auto-cmd12: specifies that controller should use auto CMD12.
+
+Example:
+
+sdhci0: sdhci at 0x18041000 {
+	compatible = "brcm,sdhci-iproc-cygnus";
+	reg = <0x18041000 0x100>;
+	interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
+	bus-width = <4>;
+	sdhci,auto-cmd12;
+	no-1-8-v;
+};
Signature · 1 line
2.2.2
#191 lore raw

Re: [PATCH 4/4] mmc: sdhci-iproc: add device tree bindings

Quoted 17 lines · Scott Branden

Add device tree binding documentation for IPROC SDHCI driver.

---
 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file +1 -0
new file mode 100644
index 0000000..72cc9cc
@@ -0,0 +1,23 @@
+Broadcom IPROC SDHCI controller

Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt line 11

Quoted 10 lines
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file +10 -0
+
+This file documents differences between the core properties described
+by mmc.txt and the properties that represent the IPROC SDHCI controller.
+
+Required properties:
+- compatible : Should be "brcm,sdhci-iproc-cygnus".
+- clocks : The clock feeding the SDHCI controller.
+
+Optional properties:
+  - sdhci,auto-cmd12: specifies that controller should use auto CMD12.

Formatting is a little different here, there is one too many space to begin the line.

Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt line 15

Quoted 4 lines
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file +4 -0
+
+Example:
+
+sdhci0: sdhci at 0x18041000 {

0x is typically dropped from this part, to only appear in the "reg" property.

Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt line 23

Quoted 9 lines
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file +8 -0
+	compatible = "brcm,sdhci-iproc-cygnus";
+	reg = <0x18041000 0x100>;
+	interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
+	bus-width = <4>;
+	sdhci,auto-cmd12;
+	no-1-8-v;
+};

Unless there is a re-spin, I will fix this myself while applying this patch to devicetree/next.

Thanks

Signature · 1 line
Florian
author maintainer
#192 lore raw

Re: [PATCH 4/4] mmc: sdhci-iproc: add device tree bindings

Hi Florian,

Quoted 6 lines · Florian Fainelli

Unless there is a re-spin, I will fix this myself while applying this patch to devicetree/next.

Thanks

Yes, you can patch the formatting if the driver is being integrated. But I have had no response or feedback on the sdhci driver. It has been sitting for 1 month.

author maintainer
#193 lore raw

Re: [PATCH 0/4] Add support for IPROC SDHCI controller

In reply to Scott Branden

Hi Chris,

I have not heard any more feedback on this patchset. Is it in your queue to review or merge into your tree?

Thanks,
Scott

Quoted 22 lines · Scott Branden

This series of patchsets contains the IPROC SDHCI driver used in a series of Broadcom SoCs
Quirks are also added to support this controller.

Corneliu Doban (1):
mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

Scott Branden (3):
mmc: sdhci: add quirk for ACMD23 broken
mmc: sdhci-iproc: add IPROC SDHCI driver
mmc: sdhci-iproc: add device tree bindings

  .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   |  23 ++
  drivers/mmc/host/Kconfig                           |  14 ++
  drivers/mmc/host/Makefile                          |   1 +
  drivers/mmc/host/sdhci-iproc.c                     | 241 +++++++++++++++++++++
  drivers/mmc/host/sdhci.c                           |   7 +-
  include/linux/mmc/sdhci.h                          |   2 +
  6 files changed, 286 insertions(+), 2 deletions(-)

create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt create mode 100644 drivers/mmc/host/sdhci-iproc.c

author maintainer
#194 lore raw

cover Add support for Broadcom RNG200

In reply to a message not in the archive

This series of patchsets contains the Broadcom Random Number Generator driver and device tree binding documentation.

Scott Branden (2):
hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver
hwrng: iproc-rng200 - Add device tree bindings

 .../bindings/hwrng/brcm,iproc-rng200.txt           |  12 ++
 drivers/char/hw_random/Kconfig                     |  13 ++
 drivers/char/hw_random/Makefile                    |   1 +
 drivers/char/hw_random/iproc-rng200.c              | 239 +++++++++++++++++++++
 4 files changed, 265 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
Signature · 1 line
2.2.2
author maintainer
#195 lore raw

PATCH 1/2 hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

This adds a driver for random number generator present on Broadcom IPROC devices.

---
 drivers/char/hw_random/Kconfig        |  13 ++
 drivers/char/hw_random/Makefile       |   1 +
 drivers/char/hw_random/iproc-rng200.c | 239 ++++++++++++++++++++++++++++++++++
 3 files changed, 253 insertions(+)
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
drivers/char/hw_random/Kconfig +13 -0
index de57b38..f48cf11 100644
@@ -101,6 +101,19 @@ config HW_RANDOM_BCM2835
 
 	  If unsure, say Y.
 
+config HW_RANDOM_IPROC_RNG200
+	tristate "Broadcom iProc RNG200 support"
+	depends on ARCH_BCM_IPROC
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the RNG200
+	  hardware found on the Broadcom iProc SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-rng200
+
+	  If unsure, say Y.
+
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
 	depends on X86_32 && PCI
drivers/char/hw_random/Makefile +1 -0
index 0b4cd57..055bb01 100644
@@ -28,5 +28,6 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_EXYNOS)	+= exynos-rng.o
 obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
 obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
drivers/char/hw_random/iproc-rng200.c new file +239 -0

239 lines not on this page · raw message

Signature · 1 line
2.2.2
#196 lore raw

Re: [PATCH 1/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Quoted 2 lines · Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

trivia:

drivers/char/hw_random/iproc-rng200.c

Quoted 1 line
drivers/char/hw_random/iproc-rng200.c +0 -0

[]

drivers/char/hw_random/iproc-rng200.c

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +2 -0
+static int iproc_rng200_probe(struct platform_device *pdev)
+{

[]

drivers/char/hw_random/iproc-rng200.c line 175

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +2 -0
+	if (!res) {
+		dev_err(dev, "failed to get rng resources");

Missing terminating newline:

		dev_err(dev, "failed to get rng resources\n");

drivers/char/hw_random/iproc-rng200.c line 181

Quoted 3 lines
drivers/char/hw_random/iproc-rng200.c +3 -0
+	rng_base = devm_ioremap_resource(dev, res);
+	if (!rng_base) {
+		dev_err(dev, "failed to remap rng regs");

here too.

author maintainer
#197 lore raw

Re: [PATCH 1/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Hi Joe,

I really don't see the missing terminating newlines in the patch or source code. The lines look the same as every other line???

Regards,
Scott

Quoted 25 lines · Joe Perches
Quoted 2 lines · Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

trivia:

drivers/char/hw_random/iproc-rng200.c

Quoted 1 line
drivers/char/hw_random/iproc-rng200.c +0 -0

[]

drivers/char/hw_random/iproc-rng200.c

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +2 -0
+static int iproc_rng200_probe(struct platform_device *pdev)
+{

[]

drivers/char/hw_random/iproc-rng200.c line 175

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +2 -0
+	if (!res) {
+		dev_err(dev, "failed to get rng resources");

Missing terminating newline:

		dev_err(dev, "failed to get rng resources\n");

drivers/char/hw_random/iproc-rng200.c line 181

Quoted 3 lines
drivers/char/hw_random/iproc-rng200.c +3 -0
+	rng_base = devm_ioremap_resource(dev, res);
+	if (!rng_base) {
+		dev_err(dev, "failed to remap rng regs");

here too.

author maintainer
#198 lore raw

Re: [PATCH 1/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

I didn't read this properly. Will add \n in the dev_err messages.

Thanks,
Scott

Quoted 36 lines · Scott Branden

Hi Joe,

I really don't see the missing terminating newlines in the patch or source code. The lines look the same as every other line???

Regards,
Scott

Quoted 26 lines · Joe Perches
Quoted 2 lines · Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

trivia:

drivers/char/hw_random/iproc-rng200.c

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +0 -0

[]

drivers/char/hw_random/iproc-rng200.c

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +2 -0
+static int iproc_rng200_probe(struct platform_device *pdev)
+{

[]

drivers/char/hw_random/iproc-rng200.c line 175

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c +2 -0
+    if (!res) {
+        dev_err(dev, "failed to get rng resources");

Missing terminating newline:

        dev_err(dev, "failed to get rng resources\n");

drivers/char/hw_random/iproc-rng200.c line 181

Quoted 3 lines
drivers/char/hw_random/iproc-rng200.c +3 -0
+    rng_base = devm_ioremap_resource(dev, res);
+    if (!rng_base) {
+        dev_err(dev, "failed to remap rng regs");

here too.

author maintainer
#199 lore raw

PATCH 2/2 hwrng: iproc-rng200 - Add device tree bindings

In reply to Scott Branden

Documents the IPROC random number generator device tree bindings used in some Broadcom chipsets.

---
 .../devicetree/bindings/hwrng/brcm,iproc-rng200.txt          | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt new file +12 -0
new file mode 100644
index 0000000..e25a456
@@ -0,0 +1,12 @@
+HWRNG support for the iproc-rng200 driver
+
+Required properties:
+- compatible : "brcm,iproc-rng200"
+- reg : base address and size of control register block
+
+Example:
+
+rng {
+        compatible = "brcm,iproc-rng200";
+        reg = <0x18032000 0x28>;
+};
Signature · 1 line
2.2.2
author maintainer
#200 lore raw

cover Add support for Broadcom keypad controller

In reply to a message not in the archive

This series of patchsets contains the Broadcom keypad controller driver and device tree binding documentation.

Scott Branden (2):
Input: bcm-keypad: add device tree bindings
Input: bcm-keypad: Add Broadcom keypad controller

 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 118 +++++
 drivers/input/keyboard/Kconfig                     |  10 +
 drivers/input/keyboard/Makefile                    |   1 +
 drivers/input/keyboard/bcm-keypad.c                | 489 +++++++++++++++++++++
 4 files changed, 618 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
Signature · 1 line
2.2.2
author maintainer
#201 lore raw

PATCH 1/2 Input: bcm-keypad: add device tree bindings

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 118 +++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +118 -0
new file mode 100644
index 0000000..645829d
@@ -0,0 +1,118 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- key-interrupt-trigger-type: The type of interrupt trigger asociated with the Keypad matrix.
+
+	KEYPAD_INTERRUPT_NO_TRIGGER	=	0
+	KEYPAD_INTERRUPT_RISING_EDGE	=	1
+	KEYPAD_INTERRUPT_FALLING_EDGE	=	2
+	KEYPAD_INTERRUPT_BOTH_EDGES	=	3
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- Keys represented as child nodes: Each key connected to the keypad
+  controller is represented as a child node to the keypad controller
+  device node and should include the following properties.
+  - row: the row number to which the key is connected.
+  - column: the column number to which the key is connected.
+  - code: the key-code to be reported when the key is pressed
+    and released.
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		key-interrupt-trigger-type = <3>;
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
Signature · 1 line
2.2.2
maintainer
#202 lore raw

Re: [PATCH 1/2] Input: bcm-keypad: add device tree bindings

Hi Scott,

Quoted 39 lines · Scott Branden

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 118 +++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +24 -0
new file mode 100644
index 0000000..645829d
@@ -0,0 +1,118 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 34

Quoted 10 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +10 -0
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- key-interrupt-trigger-type: The type of interrupt trigger asociated with the Keypad matrix.
+
+	KEYPAD_INTERRUPT_NO_TRIGGER	=	0
+	KEYPAD_INTERRUPT_RISING_EDGE	=	1
+	KEYPAD_INTERRUPT_FALLING_EDGE	=	2
+	KEYPAD_INTERRUPT_BOTH_EDGES	=	3

Can we get this data from the interrupt spec?

Quoted 13 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +12 -0
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
 
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 56

Quoted 10 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +10 -0
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7

I could swear device-specific properties should be in form of <vendor-prefix>,<property-name> to ensure it won't clash with changes on subsystem level later on. Device-tree folks, what say you?

Quoted 5 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +5 -0
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 71

Quoted 10 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +10 -0
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- Keys represented as child nodes: Each key connected to the keypad
+  controller is represented as a child node to the keypad controller
+  device node and should include the following properties.
+  - row: the row number to which the key is connected.
+  - column: the column number to which the key is connected.
+  - code: the key-code to be reported when the key is pressed
+    and released.

That does not seem to be right, linux,keymap is a list, not a subtree. I'd simply refer to Documentation/devicetree/bindings/input/matrix-keymap.txt for details.

Quoted 50 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +47 -0
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		key-interrupt-trigger-type = <3>;
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
Signature · 1 line
2.2.2

Thanks.

Signature · 1 line
Dmitry
author maintainer
#203 lore raw

Re: [PATCH 1/2] Input: bcm-keypad: add device tree bindings

Hi Dmitry,

Comments inline. I still have an issue with vendor prefix as there are not documented guidelines I can find in this area?

Quoted 46 lines · Dmitry Torokhov

Hi Scott,

Quoted 43 lines · Scott Branden

Documents the Broadcom keypad controller device tree bindings.

---
  .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 118 +++++++++++++++++++++
  1 file changed, 118 insertions(+)

create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +28 -0
new file mode 100644
index 0000000..645829d
@@ -0,0 +1,118 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
Quoted 8 lines

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 34

Quoted 6 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +6 -0
+- key-interrupt-trigger-type: The type of interrupt trigger asociated with the Keypad matrix.
+
+	KEYPAD_INTERRUPT_NO_TRIGGER	=	0
+	KEYPAD_INTERRUPT_RISING_EDGE	=	1
+	KEYPAD_INTERRUPT_FALLING_EDGE	=	2
+	KEYPAD_INTERRUPT_BOTH_EDGES	=	3

Can we get this data from the interrupt spec?

I don't understand your question. Could you elaborate? But, looking at this closer this determines when the hardware should generate interrupts. I think we would always need to set it to both edges and this binding option can probably we removed?

Quoted 20 lines
Quoted 20 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +18 -0
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
 
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
Quoted 8 lines

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 45

Quoted 4 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +4 -0
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7

I could swear device-specific properties should be in form of <vendor-prefix>,<property-name> to ensure it won't clash with changes on subsystem level later on. Device-tree folks, what say you?

I see examples with and without vendor-prefix.
qcom,pm8xxx-keypad.txt does not have prefixes
st-keyscan.txt does have a prefix

I can't find any documented guidelines for this.
Clash changes should not happen because as new standard properties are added the drivers should be adjusted to use the new dt-bindings?

Quoted 12 lines
Quoted 12 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +11 -0
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- Keys represented as child nodes: Each key connected to the keypad
+  controller is represented as a child node to the keypad controller
+  device node and should include the following properties.
Quoted 8 lines

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 71

Quoted 4 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +4 -0
+  - row: the row number to which the key is connected.
+  - column: the column number to which the key is connected.
+  - code: the key-code to be reported when the key is pressed
+    and released.

That does not seem to be right, linux,keymap is a list, not a subtree. I'd simply refer to Documentation/devicetree/bindings/input/matrix-keymap.txt for details.

Yes, we moved to matrix-keymap and forgot to update this documentation.
Will correct - thanks.

Quoted 54 lines
Quoted 49 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +47 -1
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		key-interrupt-trigger-type = <3>;
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
--
Quoted 2 lines

2.2.2

Thanks.

maintainer
#204 lore raw

Re: [PATCH 1/2] Input: bcm-keypad: add device tree bindings

Hi Scott,

Quoted 4 lines · Scott Branden

Hi Dmitry,

Comments inline. I still have an issue with vendor prefix as there are not documented guidelines I can find in this area?

I looked and I could not locate it written down either. I think Grant is in Santa Rosa this week, I'll ask him to clarify.

Quoted 57 lines · Dmitry Torokhov
Quoted 46 lines

Hi Scott,

Quoted 43 lines · Scott Branden

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 118 +++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +28 -0
new file mode 100644
index 0000000..645829d
@@ -0,0 +1,118 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
Quoted 8 lines

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 34

Quoted 6 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +6 -0
+- key-interrupt-trigger-type: The type of interrupt trigger asociated with the Keypad matrix.
+
+	KEYPAD_INTERRUPT_NO_TRIGGER	=	0
+	KEYPAD_INTERRUPT_RISING_EDGE	=	1
+	KEYPAD_INTERRUPT_FALLING_EDGE	=	2
+	KEYPAD_INTERRUPT_BOTH_EDGES	=	3

Can we get this data from the interrupt spec?

Quoted 4 lines

I don't understand your question. Could you elaborate? But, looking at this closer this determines when the hardware should generate interrupts. I think we would always need to set it to both edges and this binding option can probably we removed?

What I meant that interrupt binding allows specifying the trigger and you have separate binding for trigger here. It would be nice to have just one (the standard interrupt binding).

Quoted 28 lines
Quoted 20 lines
Quoted 20 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +18 -0
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
 
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
Quoted 8 lines

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 45

Quoted 4 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +4 -0
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7

I could swear device-specific properties should be in form of <vendor-prefix>,<property-name> to ensure it won't clash with changes on subsystem level later on. Device-tree folks, what say you?

Quoted 5 lines

I see examples with and without vendor-prefix.
qcom,pm8xxx-keypad.txt does not have prefixes
st-keyscan.txt does have a prefix

I can't find any documented guidelines for this.

As I mentioned I'll try to get clarification on this.

Quoted 2 lines

Clash changes should not happen because as new standard properties are added the drivers should be adjusted to use the new dt-bindings?

This is a misconception: device tree bindings are supposed to form ABI (and the goal to eventually separate them from the kernel) and so we need to support old bindings in new kernels.

Thanks.

Signature · 1 line
Dmitry
maintainer
#205 lore raw

Re: [PATCH 1/2] Input: bcm-keypad: add device tree bindings

Hi Scott,

Quoted 30 lines · Dmitry Torokhov
Quoted 29 lines · Scott Branden
Quoted 28 lines · Dmitry Torokhov
Quoted 13 lines · Scott Branden
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +12 -0
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
 
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 56

Quoted 10 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +10 -0
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7

I could swear device-specific properties should be in form of <vendor-prefix>,<property-name> to ensure it won't clash with changes on subsystem level later on. Device-tree folks, what say you?

Quoted 7 lines
Quoted 5 lines

I see examples with and without vendor-prefix.
qcom,pm8xxx-keypad.txt does not have prefixes
st-keyscan.txt does have a prefix

I can't find any documented guidelines for this.

As I mentioned I'll try to get clarification on this.

I have chatted with a couple of people on this and it is acceptable to omit vendor prefix in bindings when we are using a specific driver like we have here (i.e. when driver's compatible string already includes vendor prefix). Vendor prefixes on properties are required when we augment a generic driver's binding.

So the above 2 entries are fine as is.

Thanks.

Signature · 1 line
Dmitry
author maintainer
#206 lore raw

Re: [PATCH 1/2] Input: bcm-keypad: add device tree bindings

Hi Dmitry,

Thanks for the update of no need to change any of dt-binding prefixes. I just sent out a v2 patch addressing all of your other comments.

Quoted 51 lines · Dmitry Torokhov

Hi Scott,

Quoted 30 lines · Dmitry Torokhov
Quoted 29 lines · Scott Branden
Quoted 28 lines · Dmitry Torokhov
Quoted 13 lines · Scott Branden
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +12 -0
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
 
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 56

Quoted 10 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +10 -0
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7

I could swear device-specific properties should be in form of <vendor-prefix>,<property-name> to ensure it won't clash with changes on subsystem level later on. Device-tree folks, what say you?

Quoted 7 lines
Quoted 5 lines

I see examples with and without vendor-prefix.
qcom,pm8xxx-keypad.txt does not have prefixes
st-keyscan.txt does have a prefix

I can't find any documented guidelines for this.

As I mentioned I'll try to get clarification on this.

I have chatted with a couple of people on this and it is acceptable to omit vendor prefix in bindings when we are using a specific driver like we have here (i.e. when driver's compatible string already includes vendor prefix). Vendor prefixes on properties are required when we augment a generic driver's binding.

So the above 2 entries are fine as is.

Thanks.

author maintainer
#207 lore raw

PATCH 2/2 Input: bcm-keypad: Add Broadcom keypad controller

In reply to Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 489 ++++++++++++++++++++++++++++++++++++
 3 files changed, 500 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
 endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
 obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +489 -0

489 lines not on this page · raw message

Signature · 1 line
2.2.2
maintainer
#208 lore raw

Re: [PATCH 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Scott,

Quoted 196 lines · Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 489 ++++++++++++++++++++++++++++++++++++
 3 files changed, 500 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
 endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
 obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +142 -0
new file mode 100644
index 0000000..b2c4bb7
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+#include <linux/stddef.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/memory.h>
+#include <linux/io.h>
+#include <linux/input/matrix_keypad.h>
+
+#define DEFAULT_CLK_HZ                  31250
+/* Repeat period (ms) */
+#define KEY_REPEAT_PERIOD               100
+/* First time press dly (ms) */
+#define KEY_REPEAT_DELAY                400
+#define MAX_ROWS                        8
+#define MAX_COLS                        8
+
+/* Register/field definitions */
+#define KPCR_OFFSET                          0x00000080
+#define KPCR_MODE                       0x00000002
+#define KPCR_MODE_SHIFT                 1
+#define KPCR_MODE_MASK                  1
+#define KPCR_ENABLE                     0x00000001
+#define KPCR_STATUSFILTERENABLE         0x00008000
+#define KPCR_STATUSFILTERTYPE_SHIFT          12
+#define KPCR_COLFILTERENABLE            0x00000800
+#define KPCR_COLFILTERTYPE_SHIFT             8
+#define KPCR_ROWWIDTH_SHIFT                  20
+#define KPCR_COLUMNWIDTH_SHIFT               16
+
+#define KPIOR_OFFSET                         0x00000084
+#define KPIOR_ROWOCONTRL_SHIFT               24
+#define KPIOR_ROWOCONTRL_MASK                0xFF000000
+#define KPIOR_COLUMNOCONTRL_SHIFT            16
+#define KPIOR_COLUMNOCONTRL_MASK             0x00FF0000
+#define KPIOR_COLUMN_IO_DATA_SHIFT           0
+
+#define KPEMR0_OFFSET                        0x00000090
+#define KPEMR1_OFFSET                        0x00000094
+#define KPEMR2_OFFSET                        0x00000098
+#define KPEMR3_OFFSET                        0x0000009C
+#define KPEMR_EDGETYPE_MAX 3
+
+#define KPSSR0_OFFSET                        0x000000A0
+#define KPSSR1_OFFSET                        0x000000A4
+#define KPIMR0_OFFSET                        0x000000B0
+#define KPIMR1_OFFSET                        0x000000B4
+#define KPICR0_OFFSET                        0x000000B8
+#define KPICR1_OFFSET                        0x000000BC
+#define KPISR0_OFFSET                        0x000000C0
+#define KPISR1_OFFSET                        0x000000C4
+
+#define KPCR_STATUSFILTERTYPE_MAX 7
+#define KPCR_COLFILTERTYPE_MAX 7
+
+/* Macros to determine the row/column from a bit that is set in SSR0/1. */
+#define BIT_TO_ROW_SSR0(bit_nr)  (bit_nr >> 3)
+#define BIT_TO_ROW_SSR1(bit_nr)  ((bit_nr >> 3) + 4)
+#define BIT_TO_COL(bit_nr)       (bit_nr % 8)
+
+/* Structure representing various run-time entities */
+struct bcm_kp {
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	struct input_dev *input_dev;
+	unsigned long last_state[2];
+	unsigned int n_rows;
+	unsigned int n_cols;
+	u32 kpcr;
+	u32 kpior;
+	u32 kpemr;
+	u32 imr0_val;
+	u32 imr1_val;
+};
+
+/*
+ * Returns the keycode from the input device keymap given the row and
+ * column.
+ */
+static inline int bcm_kp_get_keycode(struct bcm_kp *kp, int row, int col)
+{
+	unsigned int row_shift = get_count_order(kp->n_cols);
+	unsigned short *keymap = kp->input_dev->keycode;
+
+	return keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
+}
+
+static irqreturn_t bcm_kp_isr_thread(int irq, void *dev_id)
+{
+	struct bcm_kp *kp = dev_id;
+	unsigned long state, change;
+	int bit_nr;
+	int pull_mode = (kp->kpcr >> KPCR_MODE_SHIFT) & KPCR_MODE_MASK;
+	int key_press;
+	int row, col;
+	unsigned int keycode;
+
+	/* Clear interrupts */
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	state = readl(kp->base + KPSSR0_OFFSET);
+	change = kp->last_state[0] ^ state;
+	kp->last_state[0] = state;
+
+	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
+		key_press = state & BIT(bit_nr);
+		/* The meaning of SSR register depends on pull mode. */
+		key_press = pull_mode ? !key_press : key_press;
+		row = BIT_TO_ROW_SSR0(bit_nr);
+		col = BIT_TO_COL(bit_nr);
+		keycode = bcm_kp_get_keycode(kp, row, col);
+		input_report_key(kp->input_dev, keycode, key_press);
+	}
+
+	state = readl(kp->base + KPSSR1_OFFSET);
+	change = kp->last_state[1] ^ state;
+	kp->last_state[1] = state;

drivers/input/keyboard/bcm-keypad.c line 152

Quoted 10 lines
drivers/input/keyboard/bcm-keypad.c new file +10 -0
+
+	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
+		key_press = state & BIT(bit_nr);
+		/* The meaning of SSR register depends on pull mode. */
+		key_press = pull_mode ? !key_press : key_press;
+		row = BIT_TO_ROW_SSR1(bit_nr);
+		col = BIT_TO_COL(bit_nr);
+		keycode = bcm_kp_get_keycode(kp, row, col);
+		input_report_key(kp->input_dev, keycode, key_press);
+	}

Please split it into a separate function that processes one bank and call it twice instead of doing cut-and-paste of almost the same code. Or even better combine it all into one block (i.e have changes[2], use bitmap_xor to figure difference, etc...).

Quoted 198 lines
drivers/input/keyboard/bcm-keypad.c new file +198 -0
+
+	input_sync(kp->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm_kp_start(struct bcm_kp *kp)
+{
+	int error;
+
+	error = clk_prepare_enable(kp->clk);
+	if (error)
+		return error;
+
+	writel(kp->kpior, kp->base + KPIOR_OFFSET);
+
+	writel(kp->imr0_val, kp->base + KPIMR0_OFFSET);
+	writel(kp->imr1_val, kp->base + KPIMR1_OFFSET);
+
+	writel(kp->kpemr, kp->base + KPEMR0_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR1_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR2_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR3_OFFSET);
+
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	kp->last_state[0] = readl(kp->base + KPSSR0_OFFSET);
+	kp->last_state[0] = readl(kp->base + KPSSR1_OFFSET);
+
+	writel(kp->kpcr | KPCR_ENABLE, kp->base + KPCR_OFFSET);
+
+	return 0;
+}
+
+static void bcm_kp_stop(const struct bcm_kp *kp)
+{
+	u32 val;
+
+	val = readl(kp->base + KPCR_OFFSET);
+	val &= ~KPCR_ENABLE;
+	writel(0, kp->base + KPCR_OFFSET);
+	writel(0, kp->base + KPIMR0_OFFSET);
+	writel(0, kp->base + KPIMR1_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	clk_disable_unprepare(kp->clk);
+}
+
+static int bcm_kp_open(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	return bcm_kp_start(kp);
+}
+
+static void bcm_kp_close(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	bcm_kp_stop(kp);
+}
+
+static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp)
+{
+	struct device *dev = kp->input_dev->dev.parent;
+	struct device_node *np = dev->of_node;
+	int error;
+	unsigned int dt_val;
+	unsigned int i;
+
+	/* Initialize the KPCR Keypad Configuration Register */
+	kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE;
+
+	error = matrix_keypad_parse_of_params(dev, &kp->n_rows, &kp->n_cols);
+	if (error) {
+		dev_err(dev, "failed to parse kp params\n");
+		return error;
+	}
+	/* Set row width for the ASIC block. */
+	kp->kpcr |= (kp->n_rows - 1) << KPCR_ROWWIDTH_SHIFT;
+
+	/* Set column width for the ASIC block. */
+	kp->kpcr |= (kp->n_cols - 1) << KPCR_COLUMNWIDTH_SHIFT;
+
+	/* Configure the IMR registers */
+	{
+		unsigned int num_rows, col_mask, rows_set;
+
+		/* IMR registers contain interrupt enable bits for 8x8 matrix
+		 * IMR0 register format: <row3> <row2> <row1> <row0>
+		 * IMR1 register format: <row7> <row6> <row5> <row4>
+		 */
+
+		col_mask = (1 << (kp->n_cols)) - 1;
+		num_rows = kp->n_rows;
+
+		/* Set column bits in rows 0 to 3 in IMR0 */
+		kp->imr0_val = col_mask;
+
+		rows_set = 1;
+		while ((--num_rows) && (rows_set++ < 4))
+			kp->imr0_val |= (kp->imr0_val << MAX_COLS);
+
+		/* Set column bits in rows 4 to 7 in IMR1 */
+		kp->imr1_val = 0;
+		if (num_rows) {
+			kp->imr1_val = col_mask;
+			while (--num_rows)
+				kp->imr1_val |= (kp->imr1_val << MAX_COLS);
+		}
+	}
+
+	/*
+	 * Obtain the interrupt trigger type specified and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "key-interrupt-trigger-type",
+		&dt_val);
+	if ((dt_val == 0) || (dt_val > KPEMR_EDGETYPE_MAX)) {
+		dev_err(dev, "Invalid interrupt trigger type %d\n", dt_val);
+		return -EINVAL;
+	}
+	/* Initialize the KPEMR Keypress Edge Mode Registers */
+	kp->kpemr = 0;
+	for (i = 0; i <= 30; i = i + 2)
+		kp->kpemr |= (dt_val << i);
+
+	/*
+	 * Obtain the Status filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "status-debounce-filter-period",
+		&dt_val);
+	if (dt_val > KPCR_STATUSFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Status filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_STATUSFILTERTYPE_SHIFT;
+
+
+	/*
+	 * Obtain the Column filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "col-debounce-filter-period",
+		&dt_val);
+
+	if (dt_val > KPCR_COLFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Column filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_COLFILTERTYPE_SHIFT;
+
+	/*
+	 * Determine between the row and column,
+	 * which should be configured as output.
+	 */
+	if (of_property_read_bool(np, "row-output-enabled")) {
+		/*
+		* Set RowOContrl or ColumnOContrl in KPIOR
+		* to the number of pins to drive as outputs
+		*/
+		kp->kpior = (((1 << kp->n_rows) - 1) <<
+				KPIOR_ROWOCONTRL_SHIFT);
+	} else {
+		kp->kpior = (((1 << kp->n_cols) - 1) <<
+				KPIOR_COLUMNOCONTRL_SHIFT);
+	}
+
+	/*
+	 * Determine if the scan pull up needs to be enabled
+	 */
+	if (of_property_read_bool(np, "pull-up-enabled"))
+		kp->kpcr |= KPCR_MODE;
+
+	dev_dbg(dev, "n_rows=%d n_col=%d kpcr=%x kpior=%x kpemr=%x\n",
+		kp->n_rows, kp->n_cols,
+		kp->kpcr, kp->kpior, kp->kpemr);
+
+	return 0;
+}
+
+
+static int bcm_kp_probe(struct platform_device *pdev)
+{
+	struct bcm_kp *kp;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int error;
+
+	kp = devm_kzalloc(&pdev->dev, sizeof(*kp),
+				   GFP_KERNEL);
+	if (!kp)
+		return -ENOMEM;

drivers/input/keyboard/bcm-keypad.c line 360

Quoted 10 lines
drivers/input/keyboard/bcm-keypad.c new file +10 -0
+
+	input_dev = devm_input_allocate_device(&pdev->dev);
+	if (!input_dev) {
+		dev_err(&pdev->dev, "failed to allocate the input device\n");
+		return -ENOMEM;
+	}
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(EV_REP, input_dev->evbit);
+	input_dev->rep[REP_PERIOD] = KEY_REPEAT_PERIOD;
+	input_dev->rep[REP_DELAY] = KEY_REPEAT_DELAY;

That does not do what you think: if you set up custom delay and period you are supposed to supply your own timer as well. Either adjust values after registering input device, or leave defaults.

Also it might be a good idea to have "linux,autorepeat" DT property to control it.

Quoted 95 lines
drivers/input/keyboard/bcm-keypad.c new file +95 -0
+	input_dev->name = pdev->name;
+	input_dev->phys = "keypad/input0";
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = bcm_kp_open;
+	input_dev->close = bcm_kp_close;
+
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+
+	input_set_drvdata(input_dev, kp);
+
+	kp->input_dev = input_dev;
+
+	platform_set_drvdata(pdev, kp);
+
+	error = bcm_kp_matrix_key_parse_dt(kp);
+	if (error)
+		return error;
+
+	error = matrix_keypad_build_keymap(NULL, NULL,
+					   kp->n_rows,
+					   kp->n_cols,
+					   NULL, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		return error;
+	}
+
+	/* Get the KEYPAD base address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Missing keypad base address resource\n");
+		return -ENODEV;
+	}
+
+	kp->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kp->base))
+		return PTR_ERR(kp->base);
+
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk))
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");
+	else {
+		unsigned int desired_rate;
+		long actual_rate;
+
+		error = of_property_read_u32(pdev->dev.of_node,
+				"clock-frequency", &desired_rate);
+		if (error < 0)
+			desired_rate = DEFAULT_CLK_HZ;
+
+		actual_rate = clk_round_rate(kp->clk, desired_rate);
+		if (actual_rate <= 0)
+			return -EINVAL;
+
+		error = clk_set_rate(kp->clk, actual_rate);
+		if (error)
+			return -EINVAL;
+
+		error = clk_prepare_enable(kp->clk);
+		if (error)
+			return -EINVAL;
+	}
+
+	/* Put the kp into a known sane state */
+	bcm_kp_stop(kp);
+
+	kp->irq = platform_get_irq(pdev, 0);
+	if (kp->irq < 0) {
+		dev_err(&pdev->dev, "no IRQ specified\n");
+		return -EINVAL;
+	}
+
+	error = devm_request_threaded_irq(&pdev->dev, kp->irq, NULL,
+		bcm_kp_isr_thread,
+		IRQF_ONESHOT, pdev->name, kp);
+	if (error) {
+		dev_err(&pdev->dev, "failed to request IRQ\n");
+		return error;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register input device\n");
+		return error;
+	}
+
+	return 0;
+}
+

drivers/input/keyboard/bcm-keypad.c line 465

Quoted 10 lines
drivers/input/keyboard/bcm-keypad.c new file +10 -0
+/* Called to perform module cleanup when the module is unloaded. */
+static int bcm_kp_remove(struct platform_device *pdev)
+{
+	struct bcm_kp *kp = platform_get_drvdata(pdev);
+
+	pr_info("bcm_kp_remove\n");
+
+	/* Unregister everything */
+	input_unregister_device(kp->input_dev);
+	clk_disable_unprepare(kp->clk);

You already calling clk_disable_unprepare() as part of bcm_kp_close() (in stop()), so you do not need it here. input_unregister_device() will also be called automatically since you are using managed input device, so please remove bcm_kp_remove altogether.

Quoted 27 lines
drivers/input/keyboard/bcm-keypad.c new file +24 -0
+
+	return 0;
+}
+
+static const struct of_device_id bcm_kp_of_match[] = {
+	{ .compatible = "brcm,bcm-keypad" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bcm_kp_of_match);
+
+static struct platform_driver bcm_kp_device_driver = {
+	.probe		= bcm_kp_probe,
+	.remove = bcm_kp_remove,
+	.driver		= {
+		.name	= "bcm-keypad",
+		.of_match_table = of_match_ptr(bcm_kp_of_match),
+	}
+};
+
+module_platform_driver(bcm_kp_device_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("BCM Keypad Driver");
+MODULE_LICENSE("GPL");
Signature · 1 line
2.2.2

Thanks.

Signature · 1 line
Dmitry
author maintainer
#209 lore raw

Re: [PATCH 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Dmitry,

Good review. Thanks. Commented inline.

Quoted 206 lines · Dmitry Torokhov

Hi Scott,

Quoted 203 lines · Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
  drivers/input/keyboard/Kconfig      |  10 +
  drivers/input/keyboard/Makefile     |   1 +
  drivers/input/keyboard/bcm-keypad.c | 489 ++++++++++++++++++++++++++++++++++++
  3 files changed, 500 insertions(+)

create mode 100644 drivers/input/keyboard/bcm-keypad.c

drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
  	  To compile this driver as a module, choose M here: the
  	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
  endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
  obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
  obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
  obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
  obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
  obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
  obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +149 -0
new file mode 100644
index 0000000..b2c4bb7
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+#include <linux/stddef.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/memory.h>
+#include <linux/io.h>
+#include <linux/input/matrix_keypad.h>
+
+#define DEFAULT_CLK_HZ                  31250
+/* Repeat period (ms) */
+#define KEY_REPEAT_PERIOD               100
+/* First time press dly (ms) */
+#define KEY_REPEAT_DELAY                400
+#define MAX_ROWS                        8
+#define MAX_COLS                        8
+
+/* Register/field definitions */
+#define KPCR_OFFSET                          0x00000080
+#define KPCR_MODE                       0x00000002
+#define KPCR_MODE_SHIFT                 1
+#define KPCR_MODE_MASK                  1
+#define KPCR_ENABLE                     0x00000001
+#define KPCR_STATUSFILTERENABLE         0x00008000
+#define KPCR_STATUSFILTERTYPE_SHIFT          12
+#define KPCR_COLFILTERENABLE            0x00000800
+#define KPCR_COLFILTERTYPE_SHIFT             8
+#define KPCR_ROWWIDTH_SHIFT                  20
+#define KPCR_COLUMNWIDTH_SHIFT               16
+
+#define KPIOR_OFFSET                         0x00000084
+#define KPIOR_ROWOCONTRL_SHIFT               24
+#define KPIOR_ROWOCONTRL_MASK                0xFF000000
+#define KPIOR_COLUMNOCONTRL_SHIFT            16
+#define KPIOR_COLUMNOCONTRL_MASK             0x00FF0000
+#define KPIOR_COLUMN_IO_DATA_SHIFT           0
+
+#define KPEMR0_OFFSET                        0x00000090
+#define KPEMR1_OFFSET                        0x00000094
+#define KPEMR2_OFFSET                        0x00000098
+#define KPEMR3_OFFSET                        0x0000009C
+#define KPEMR_EDGETYPE_MAX 3
+
+#define KPSSR0_OFFSET                        0x000000A0
+#define KPSSR1_OFFSET                        0x000000A4
+#define KPIMR0_OFFSET                        0x000000B0
+#define KPIMR1_OFFSET                        0x000000B4
+#define KPICR0_OFFSET                        0x000000B8
+#define KPICR1_OFFSET                        0x000000BC
+#define KPISR0_OFFSET                        0x000000C0
+#define KPISR1_OFFSET                        0x000000C4
+
+#define KPCR_STATUSFILTERTYPE_MAX 7
+#define KPCR_COLFILTERTYPE_MAX 7
+
+/* Macros to determine the row/column from a bit that is set in SSR0/1. */
+#define BIT_TO_ROW_SSR0(bit_nr)  (bit_nr >> 3)
+#define BIT_TO_ROW_SSR1(bit_nr)  ((bit_nr >> 3) + 4)
+#define BIT_TO_COL(bit_nr)       (bit_nr % 8)
+
+/* Structure representing various run-time entities */
+struct bcm_kp {
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	struct input_dev *input_dev;
+	unsigned long last_state[2];
+	unsigned int n_rows;
+	unsigned int n_cols;
+	u32 kpcr;
+	u32 kpior;
+	u32 kpemr;
+	u32 imr0_val;
+	u32 imr1_val;
+};
+
+/*
+ * Returns the keycode from the input device keymap given the row and
+ * column.
+ */
+static inline int bcm_kp_get_keycode(struct bcm_kp *kp, int row, int col)
+{
+	unsigned int row_shift = get_count_order(kp->n_cols);
+	unsigned short *keymap = kp->input_dev->keycode;
+
+	return keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
+}
+
+static irqreturn_t bcm_kp_isr_thread(int irq, void *dev_id)
+{
+	struct bcm_kp *kp = dev_id;
+	unsigned long state, change;
+	int bit_nr;
+	int pull_mode = (kp->kpcr >> KPCR_MODE_SHIFT) & KPCR_MODE_MASK;
+	int key_press;
+	int row, col;
+	unsigned int keycode;
+
+	/* Clear interrupts */
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	state = readl(kp->base + KPSSR0_OFFSET);
+	change = kp->last_state[0] ^ state;
+	kp->last_state[0] = state;
+
+	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
+		key_press = state & BIT(bit_nr);
+		/* The meaning of SSR register depends on pull mode. */
+		key_press = pull_mode ? !key_press : key_press;
+		row = BIT_TO_ROW_SSR0(bit_nr);
+		col = BIT_TO_COL(bit_nr);
+		keycode = bcm_kp_get_keycode(kp, row, col);
+		input_report_key(kp->input_dev, keycode, key_press);
+	}
+
+	state = readl(kp->base + KPSSR1_OFFSET);
+	change = kp->last_state[1] ^ state;
+	kp->last_state[1] = state;
+
+	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
+		key_press = state & BIT(bit_nr);
+		/* The meaning of SSR register depends on pull mode. */
+		key_press = pull_mode ? !key_press : key_press;
+		row = BIT_TO_ROW_SSR1(bit_nr);
+		col = BIT_TO_COL(bit_nr);
Quoted 9 lines

drivers/input/keyboard/bcm-keypad.c line 138

Quoted 3 lines
drivers/input/keyboard/bcm-keypad.c new file +3 -0
+		keycode = bcm_kp_get_keycode(kp, row, col);
+		input_report_key(kp->input_dev, keycode, key_press);
+	}

Please split it into a separate function that processes one bank and call it twice instead of doing cut-and-paste of almost the same code. Or even better combine it all into one block (i.e have changes[2], use bitmap_xor to figure difference, etc...).

OK. It was a few lines of code called twice but I'll change it.

Quoted 213 lines
Quoted 198 lines
drivers/input/keyboard/bcm-keypad.c new file +198 -0
+
+	input_sync(kp->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm_kp_start(struct bcm_kp *kp)
+{
+	int error;
+
+	error = clk_prepare_enable(kp->clk);
+	if (error)
+		return error;
+
+	writel(kp->kpior, kp->base + KPIOR_OFFSET);
+
+	writel(kp->imr0_val, kp->base + KPIMR0_OFFSET);
+	writel(kp->imr1_val, kp->base + KPIMR1_OFFSET);
+
+	writel(kp->kpemr, kp->base + KPEMR0_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR1_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR2_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR3_OFFSET);
+
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	kp->last_state[0] = readl(kp->base + KPSSR0_OFFSET);
+	kp->last_state[0] = readl(kp->base + KPSSR1_OFFSET);
+
+	writel(kp->kpcr | KPCR_ENABLE, kp->base + KPCR_OFFSET);
+
+	return 0;
+}
+
+static void bcm_kp_stop(const struct bcm_kp *kp)
+{
+	u32 val;
+
+	val = readl(kp->base + KPCR_OFFSET);
+	val &= ~KPCR_ENABLE;
+	writel(0, kp->base + KPCR_OFFSET);
+	writel(0, kp->base + KPIMR0_OFFSET);
+	writel(0, kp->base + KPIMR1_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	clk_disable_unprepare(kp->clk);
+}
+
+static int bcm_kp_open(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	return bcm_kp_start(kp);
+}
+
+static void bcm_kp_close(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	bcm_kp_stop(kp);
+}
+
+static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp)
+{
+	struct device *dev = kp->input_dev->dev.parent;
+	struct device_node *np = dev->of_node;
+	int error;
+	unsigned int dt_val;
+	unsigned int i;
+
+	/* Initialize the KPCR Keypad Configuration Register */
+	kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE;
+
+	error = matrix_keypad_parse_of_params(dev, &kp->n_rows, &kp->n_cols);
+	if (error) {
+		dev_err(dev, "failed to parse kp params\n");
+		return error;
+	}
+	/* Set row width for the ASIC block. */
+	kp->kpcr |= (kp->n_rows - 1) << KPCR_ROWWIDTH_SHIFT;
+
+	/* Set column width for the ASIC block. */
+	kp->kpcr |= (kp->n_cols - 1) << KPCR_COLUMNWIDTH_SHIFT;
+
+	/* Configure the IMR registers */
+	{
+		unsigned int num_rows, col_mask, rows_set;
+
+		/* IMR registers contain interrupt enable bits for 8x8 matrix
+		 * IMR0 register format: <row3> <row2> <row1> <row0>
+		 * IMR1 register format: <row7> <row6> <row5> <row4>
+		 */
+
+		col_mask = (1 << (kp->n_cols)) - 1;
+		num_rows = kp->n_rows;
+
+		/* Set column bits in rows 0 to 3 in IMR0 */
+		kp->imr0_val = col_mask;
+
+		rows_set = 1;
+		while ((--num_rows) && (rows_set++ < 4))
+			kp->imr0_val |= (kp->imr0_val << MAX_COLS);
+
+		/* Set column bits in rows 4 to 7 in IMR1 */
+		kp->imr1_val = 0;
+		if (num_rows) {
+			kp->imr1_val = col_mask;
+			while (--num_rows)
+				kp->imr1_val |= (kp->imr1_val << MAX_COLS);
+		}
+	}
+
+	/*
+	 * Obtain the interrupt trigger type specified and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "key-interrupt-trigger-type",
+		&dt_val);
+	if ((dt_val == 0) || (dt_val > KPEMR_EDGETYPE_MAX)) {
+		dev_err(dev, "Invalid interrupt trigger type %d\n", dt_val);
+		return -EINVAL;
+	}
+	/* Initialize the KPEMR Keypress Edge Mode Registers */
+	kp->kpemr = 0;
+	for (i = 0; i <= 30; i = i + 2)
+		kp->kpemr |= (dt_val << i);
+
+	/*
+	 * Obtain the Status filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "status-debounce-filter-period",
+		&dt_val);
+	if (dt_val > KPCR_STATUSFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Status filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_STATUSFILTERTYPE_SHIFT;
+
+
+	/*
+	 * Obtain the Column filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "col-debounce-filter-period",
+		&dt_val);
+
+	if (dt_val > KPCR_COLFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Column filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_COLFILTERTYPE_SHIFT;
+
+	/*
+	 * Determine between the row and column,
+	 * which should be configured as output.
+	 */
+	if (of_property_read_bool(np, "row-output-enabled")) {
+		/*
+		* Set RowOContrl or ColumnOContrl in KPIOR
+		* to the number of pins to drive as outputs
+		*/
+		kp->kpior = (((1 << kp->n_rows) - 1) <<
+				KPIOR_ROWOCONTRL_SHIFT);
+	} else {
+		kp->kpior = (((1 << kp->n_cols) - 1) <<
+				KPIOR_COLUMNOCONTRL_SHIFT);
+	}
+
+	/*
+	 * Determine if the scan pull up needs to be enabled
+	 */
+	if (of_property_read_bool(np, "pull-up-enabled"))
+		kp->kpcr |= KPCR_MODE;
+
+	dev_dbg(dev, "n_rows=%d n_col=%d kpcr=%x kpior=%x kpemr=%x\n",
+		kp->n_rows, kp->n_cols,
+		kp->kpcr, kp->kpior, kp->kpemr);
+
+	return 0;
+}
+
+
+static int bcm_kp_probe(struct platform_device *pdev)
+{
+	struct bcm_kp *kp;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int error;
+
+	kp = devm_kzalloc(&pdev->dev, sizeof(*kp),
+				   GFP_KERNEL);
+	if (!kp)
+		return -ENOMEM;

drivers/input/keyboard/bcm-keypad.c line 360

Quoted 10 lines
drivers/input/keyboard/bcm-keypad.c new file +10 -0
+
+	input_dev = devm_input_allocate_device(&pdev->dev);
+	if (!input_dev) {
+		dev_err(&pdev->dev, "failed to allocate the input device\n");
+		return -ENOMEM;
+	}
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(EV_REP, input_dev->evbit);
+	input_dev->rep[REP_PERIOD] = KEY_REPEAT_PERIOD;
+	input_dev->rep[REP_DELAY] = KEY_REPEAT_DELAY;

That does not do what you think: if you set up custom delay and period you are supposed to supply your own timer as well. Either adjust values after registering input device, or leave defaults.

Quoted 3 lines

Also it might be a good idea to have "linux,autorepeat" DT property to control it.

I'll look into this in more detail to understand.

Quoted 102 lines
Quoted 102 lines
drivers/input/keyboard/bcm-keypad.c new file +102 -0
+	input_dev->name = pdev->name;
+	input_dev->phys = "keypad/input0";
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = bcm_kp_open;
+	input_dev->close = bcm_kp_close;
+
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+
+	input_set_drvdata(input_dev, kp);
+
+	kp->input_dev = input_dev;
+
+	platform_set_drvdata(pdev, kp);
+
+	error = bcm_kp_matrix_key_parse_dt(kp);
+	if (error)
+		return error;
+
+	error = matrix_keypad_build_keymap(NULL, NULL,
+					   kp->n_rows,
+					   kp->n_cols,
+					   NULL, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		return error;
+	}
+
+	/* Get the KEYPAD base address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Missing keypad base address resource\n");
+		return -ENODEV;
+	}
+
+	kp->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kp->base))
+		return PTR_ERR(kp->base);
+
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk))
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");
+	else {
+		unsigned int desired_rate;
+		long actual_rate;
+
+		error = of_property_read_u32(pdev->dev.of_node,
+				"clock-frequency", &desired_rate);
+		if (error < 0)
+			desired_rate = DEFAULT_CLK_HZ;
+
+		actual_rate = clk_round_rate(kp->clk, desired_rate);
+		if (actual_rate <= 0)
+			return -EINVAL;
+
+		error = clk_set_rate(kp->clk, actual_rate);
+		if (error)
+			return -EINVAL;
+
+		error = clk_prepare_enable(kp->clk);
+		if (error)
+			return -EINVAL;
+	}
+
+	/* Put the kp into a known sane state */
+	bcm_kp_stop(kp);
+
+	kp->irq = platform_get_irq(pdev, 0);
+	if (kp->irq < 0) {
+		dev_err(&pdev->dev, "no IRQ specified\n");
+		return -EINVAL;
+	}
+
+	error = devm_request_threaded_irq(&pdev->dev, kp->irq, NULL,
+		bcm_kp_isr_thread,
+		IRQF_ONESHOT, pdev->name, kp);
+	if (error) {
+		dev_err(&pdev->dev, "failed to request IRQ\n");
+		return error;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register input device\n");
+		return error;
+	}
+
+	return 0;
+}
+
+/* Called to perform module cleanup when the module is unloaded. */
+static int bcm_kp_remove(struct platform_device *pdev)
+{
+	struct bcm_kp *kp = platform_get_drvdata(pdev);
+
+	pr_info("bcm_kp_remove\n");
+
Quoted 9 lines

drivers/input/keyboard/bcm-keypad.c line 465

Quoted 3 lines
drivers/input/keyboard/bcm-keypad.c new file +3 -0
+	/* Unregister everything */
+	input_unregister_device(kp->input_dev);
+	clk_disable_unprepare(kp->clk);

You already calling clk_disable_unprepare() as part of bcm_kp_close() (in stop()), so you do not need it here. input_unregister_device() will also be called automatically since you are using managed input device, so please remove bcm_kp_remove altogether.

OK, will remove. That's an easy thing to do.

Quoted 30 lines
Quoted 25 lines
drivers/input/keyboard/bcm-keypad.c new file +24 -1
+
+	return 0;
+}
+
+static const struct of_device_id bcm_kp_of_match[] = {
+	{ .compatible = "brcm,bcm-keypad" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bcm_kp_of_match);
+
+static struct platform_driver bcm_kp_device_driver = {
+	.probe		= bcm_kp_probe,
+	.remove = bcm_kp_remove,
+	.driver		= {
+		.name	= "bcm-keypad",
+		.of_match_table = of_match_ptr(bcm_kp_of_match),
+	}
+};
+
+module_platform_driver(bcm_kp_device_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("BCM Keypad Driver");
+MODULE_LICENSE("GPL");
--
Quoted 2 lines

2.2.2

Thanks.

author maintainer
#210 lore raw

v2 cover Add support for Broadcom RNG200

In reply to a message not in the archive

This series of patchsets contains the Broadcom Random Number Generator driver and device tree binding documentation.

Changes from v1:
added \n to 2 dev_err messages

Scott Branden (2):
hwrng: iproc-rng200 - Add device tree bindings
hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

 .../bindings/hwrng/brcm,iproc-rng200.txt           |  12 ++
 drivers/char/hw_random/Kconfig                     |  13 ++
 drivers/char/hw_random/Makefile                    |   1 +
 drivers/char/hw_random/iproc-rng200.c              | 239 +++++++++++++++++++++
 4 files changed, 265 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
Signature · 1 line
2.3.0
author maintainer
#211 lore raw

PATCH v2 1/2 hwrng: iproc-rng200 - Add device tree bindings

Documents the IPROC random number generator device tree bindings used in some Broadcom chipsets.

---
 .../devicetree/bindings/hwrng/brcm,iproc-rng200.txt          | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt new file +12 -0
new file mode 100644
index 0000000..e25a456
@@ -0,0 +1,12 @@
+HWRNG support for the iproc-rng200 driver
+
+Required properties:
+- compatible : "brcm,iproc-rng200"
+- reg : base address and size of control register block
+
+Example:
+
+rng {
+        compatible = "brcm,iproc-rng200";
+        reg = <0x18032000 0x28>;
+};
Signature · 1 line
2.3.0
author maintainer
#213 lore raw

PATCH v2 2/2 hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

In reply to Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

---
 drivers/char/hw_random/Kconfig        |  13 ++
 drivers/char/hw_random/Makefile       |   1 +
 drivers/char/hw_random/iproc-rng200.c | 239 ++++++++++++++++++++++++++++++++++
 3 files changed, 253 insertions(+)
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
drivers/char/hw_random/Kconfig +13 -0
index de57b38..f48cf11 100644
@@ -101,6 +101,19 @@ config HW_RANDOM_BCM2835
 
 	  If unsure, say Y.
 
+config HW_RANDOM_IPROC_RNG200
+	tristate "Broadcom iProc RNG200 support"
+	depends on ARCH_BCM_IPROC
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the RNG200
+	  hardware found on the Broadcom iProc SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-rng200
+
+	  If unsure, say Y.
+
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
 	depends on X86_32 && PCI
drivers/char/hw_random/Makefile +1 -0
index 0b4cd57..055bb01 100644
@@ -28,5 +28,6 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_EXYNOS)	+= exynos-rng.o
 obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
 obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
drivers/char/hw_random/iproc-rng200.c new file +239 -0

239 lines not on this page · raw message

Signature · 1 line
2.3.0
#214 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Hi Scott,

Quoted 205 lines · Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

---
 drivers/char/hw_random/Kconfig        |  13 ++
 drivers/char/hw_random/Makefile       |   1 +
 drivers/char/hw_random/iproc-rng200.c | 239 ++++++++++++++++++++++++++++++++++
 3 files changed, 253 insertions(+)
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
drivers/char/hw_random/Kconfig +13 -0
index de57b38..f48cf11 100644
@@ -101,6 +101,19 @@ config HW_RANDOM_BCM2835
 
 	  If unsure, say Y.
 
+config HW_RANDOM_IPROC_RNG200
+	tristate "Broadcom iProc RNG200 support"
+	depends on ARCH_BCM_IPROC
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the RNG200
+	  hardware found on the Broadcom iProc SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-rng200
+
+	  If unsure, say Y.
+
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
 	depends on X86_32 && PCI
drivers/char/hw_random/Makefile +1 -0
index 0b4cd57..055bb01 100644
@@ -28,5 +28,6 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_EXYNOS)	+= exynos-rng.o
 obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
 obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
drivers/char/hw_random/iproc-rng200.c new file +152 -0
new file mode 100644
index 0000000..4643aa9
@@ -0,0 +1,239 @@
+/*
+* Copyright (C) 2014 Broadcom Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+/*
+ * DESCRIPTION: The Broadcom iProc RNG200 Driver
+ */
+
+#include <linux/hw_random.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+
+/* Registers */
+#define RNG_CTRL_OFFSET					0x00
+#define RNG_CTRL_RNG_RBGEN_MASK				0x00001FFF
+#define RNG_CTRL_RNG_RBGEN_ENABLE			0x00000001
+#define RNG_CTRL_RNG_RBGEN_DISABLE			0x00000000
+
+#define RNG_SOFT_RESET_OFFSET				0x04
+#define RNG_SOFT_RESET_RNG_SOFT_RESET_MASK		0x00000001
+#define RNG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE		0x00000001
+#define RNG_SOFT_RESET_RNG_SOFT_RESET_CLEAR		0x00000000
+
+#define RBG_SOFT_RESET_OFFSET				0x08
+#define RBG_SOFT_RESET_RNG_SOFT_RESET_MASK		0x00000001
+#define RBG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE		0x00000001
+#define RBG_SOFT_RESET_RNG_SOFT_RESET_CLEAR		0x00000000
+
+#define RNG_INT_STATUS_OFFSET				0x18
+#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK	0x80000000
+#define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK	0x00020000
+#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK		0x00000020
+#define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK	0x00000001
+
+#define RNG_FIFO_DATA_OFFSET				0x20
+
+#define RNG_FIFO_COUNT_OFFSET				0x24
+#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK		0x000000FF
+
+static void iproc_rng200_restart(void __iomem *rng_base)
+{
+	uint32_t val;
+
+	/* Disable RBG */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_DISABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);
+
+	/* Clear all interrupt status */
+	iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);
+
+	/* Reset RNG and RBG */
+	val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
+	val &= ~RBG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RBG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE;
+	iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+	val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
+	val &= ~RNG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RNG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE;
+	iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+	val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
+	val &= ~RNG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RNG_SOFT_RESET_RNG_SOFT_RESET_CLEAR;
+	iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+	val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
+	val &= ~RBG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RBG_SOFT_RESET_RNG_SOFT_RESET_CLEAR;
+	iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+	/* Enable RBG */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_ENABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);
+}
+
+static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max,
+			       bool wait)
+{
+	uint32_t status = 0;
+	uint32_t num_remaining = max;
+
+	#define MAX_RESETS_PER_READ	1
+	uint32_t num_resets = 0;
+
+	#define MAX_IDLE_TIME	(1 * HZ)
+	unsigned long idle_endtime = jiffies + MAX_IDLE_TIME;
+
+	/* Retrieve HW RNG registers base address. */
+	void __iomem *rng_base = (void __iomem *)rng->priv;
+
+	while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {
+
+		/* Is RNG sane? If not, reset it. */
+		status = ioread32(rng_base + RNG_INT_STATUS_OFFSET);
+		if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
+			RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {
+
+			if (num_resets >= MAX_RESETS_PER_READ)
+				return max - num_remaining;
+
+			iproc_rng200_restart(rng_base);
+			num_resets++;
+		}
+
+		/* Are there any random numbers available? */
+		if ((ioread32(rng_base + RNG_FIFO_COUNT_OFFSET) &
+				RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {
+
+			if (num_remaining >= sizeof(uint32_t)) {
+				/* Buffer has room to store entire word */
+				*(uint32_t *)buf = ioread32(rng_base +
+							RNG_FIFO_DATA_OFFSET);
+				buf += sizeof(uint32_t);
+				num_remaining -= sizeof(uint32_t);
+			} else {
+				/* Buffer can only store partial word */
+				uint32_t rnd_number = ioread32(rng_base +
+							RNG_FIFO_DATA_OFFSET);
+				memcpy(buf, &rnd_number, num_remaining);
+				buf += num_remaining;
+				num_remaining = 0;
+			}
+
+			/* Reset the IDLE timeout */
+			idle_endtime = jiffies + MAX_IDLE_TIME;
+		} else {
+			if (!wait)
+				/* Cannot wait, return immediately */
+				return max - num_remaining;
+
+			/* Can wait, give others chance to run */
+			cpu_relax();

drivers/char/hw_random/iproc-rng200.c line 162

Quoted 10 lines
drivers/char/hw_random/iproc-rng200.c new file +10 -0
+		}
+	}
+
+	return max - num_remaining;
+}
+
+static struct hwrng iproc_rng200_ops = {
+	.name	= "iproc-rng200",
+	.read	= iproc_rng200_read,
+};

I would prefer if we allocated a driver-private structure that wraps hwrng instead of using statically allocated singleton as I wonder how it will behave if I bind/unbind the device several times.

drivers/char/hw_random/iproc-rng200.c line 169

Quoted 7 lines
drivers/char/hw_random/iproc-rng200.c new file +7 -0
+
+static int iproc_rng200_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	void __iomem *rng_base = 0;
+	uint32_t val = 0;
+	int err = 0;

There is no need to initialize all variables as it suppressed "used but uninitialized" warnings from the compiler. Imagine someone adding a new init operation and when they handle failure they forget to adjust error code so it stays 0: for upper layers we'd signal success even though our device/driver are half-bound.

drivers/char/hw_random/iproc-rng200.c line 176

Quoted 7 lines
drivers/char/hw_random/iproc-rng200.c new file +7 -0
+
+	/* Map peripheral */
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(dev, "failed to get rng resources\n");
+		return -ENODEV;

If we have platform device but it is missing parts of necessary data it should be -EINVAL.

drivers/char/hw_random/iproc-rng200.c line 180

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+	}
+
+	rng_base = devm_ioremap_resource(dev, res);
+	if (!rng_base) {

devm_ioremap_resource() returns ERR_PTR-encoded result, you need to check with IS_ERR().

drivers/char/hw_random/iproc-rng200.c line 182

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c new file +2 -0
+		dev_err(dev, "failed to remap rng regs\n");
+		return -ENODEV;
		return PTR_ERR(rng_base);

drivers/char/hw_random/iproc-rng200.c line 183

Quoted 1 line
drivers/char/hw_random/iproc-rng200.c new file +1 -0
+	}

There is no clock for RNG?

drivers/char/hw_random/iproc-rng200.c line 191

Quoted 8 lines
drivers/char/hw_random/iproc-rng200.c new file +8 -0
+
+	iproc_rng200_ops.priv = (unsigned long)rng_base;
+
+	/* Setup RNG. */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_ENABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);

That should be in [new] iproc_rng200_init().

Quoted 15 lines
drivers/char/hw_random/iproc-rng200.c new file +15 -0
+
+	/* Register driver */
+	err = hwrng_register(&iproc_rng200_ops);
+	if (err) {
+		dev_err(dev, "hwrng registration failed\n");
+		return err;
+	}
+	dev_info(dev, "hwrng registered\n");
+
+	return 0;
+}
+
+static int iproc_rng200_remove(struct platform_device *pdev)
+{
+	uint32_t val = 0;

drivers/char/hw_random/iproc-rng200.c line 216

Quoted 10 lines
drivers/char/hw_random/iproc-rng200.c new file +10 -0
+	void __iomem *rng_base = (void __iomem *)iproc_rng200_ops.priv;
+
+	/* Unregister driver */
+	hwrng_unregister(&iproc_rng200_ops);
+
+	/* Disable RNG hardware */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_DISABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);

That should be in [new] iproc_rng200_cleanup().

drivers/char/hw_random/iproc-rng200.c line 203

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+
+	return 0;
+}
+

#ifdef CONFIG_OF

maybe?

Quoted 22 lines
drivers/char/hw_random/iproc-rng200.c new file +19 -0
+static const struct of_device_id iproc_rng200_of_match[] = {
+	{ .compatible = "brcm,iproc-rng200", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
+
+static struct platform_driver iproc_rng200_driver = {
+	.driver = {
+		.name = "iproc-rng200",
+		.of_match_table = iproc_rng200_of_match,
+	},
+	.probe		= iproc_rng200_probe,
+	.remove		= iproc_rng200_remove,
+};
+module_platform_driver(iproc_rng200_driver);
+
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver");
+MODULE_LICENSE("GPL v2");
Signature · 1 line
2.3.0

Thanks.

Signature · 1 line
Dmitry
author maintainer
#215 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Hi Dmitry,

Looking at the driver based on your comments it is following models of older hwrng drivers. I will work on cleaning up based on your comments as well.

Quoted 214 lines · Dmitry Torokhov

Hi Scott,

Quoted 211 lines · Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

---
  drivers/char/hw_random/Kconfig        |  13 ++
  drivers/char/hw_random/Makefile       |   1 +
  drivers/char/hw_random/iproc-rng200.c | 239 ++++++++++++++++++++++++++++++++++
  3 files changed, 253 insertions(+)

create mode 100644 drivers/char/hw_random/iproc-rng200.c

drivers/char/hw_random/Kconfig +13 -0
index de57b38..f48cf11 100644
@@ -101,6 +101,19 @@ config HW_RANDOM_BCM2835
 
  	  If unsure, say Y.
 
+config HW_RANDOM_IPROC_RNG200
+	tristate "Broadcom iProc RNG200 support"
+	depends on ARCH_BCM_IPROC
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the RNG200
+	  hardware found on the Broadcom iProc SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-rng200
+
+	  If unsure, say Y.
+
  config HW_RANDOM_GEODE
  	tristate "AMD Geode HW Random Number Generator support"
  	depends on X86_32 && PCI
drivers/char/hw_random/Makefile +1 -0
index 0b4cd57..055bb01 100644
@@ -28,5 +28,6 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
  obj-$(CONFIG_HW_RANDOM_EXYNOS)	+= exynos-rng.o
  obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
  obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
  obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
  obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
drivers/char/hw_random/iproc-rng200.c new file +158 -0
new file mode 100644
index 0000000..4643aa9
@@ -0,0 +1,239 @@
+/*
+* Copyright (C) 2014 Broadcom Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+/*
+ * DESCRIPTION: The Broadcom iProc RNG200 Driver
+ */
+
+#include <linux/hw_random.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+
+/* Registers */
+#define RNG_CTRL_OFFSET					0x00
+#define RNG_CTRL_RNG_RBGEN_MASK				0x00001FFF
+#define RNG_CTRL_RNG_RBGEN_ENABLE			0x00000001
+#define RNG_CTRL_RNG_RBGEN_DISABLE			0x00000000
+
+#define RNG_SOFT_RESET_OFFSET				0x04
+#define RNG_SOFT_RESET_RNG_SOFT_RESET_MASK		0x00000001
+#define RNG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE		0x00000001
+#define RNG_SOFT_RESET_RNG_SOFT_RESET_CLEAR		0x00000000
+
+#define RBG_SOFT_RESET_OFFSET				0x08
+#define RBG_SOFT_RESET_RNG_SOFT_RESET_MASK		0x00000001
+#define RBG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE		0x00000001
+#define RBG_SOFT_RESET_RNG_SOFT_RESET_CLEAR		0x00000000
+
+#define RNG_INT_STATUS_OFFSET				0x18
+#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK	0x80000000
+#define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK	0x00020000
+#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK		0x00000020
+#define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK	0x00000001
+
+#define RNG_FIFO_DATA_OFFSET				0x20
+
+#define RNG_FIFO_COUNT_OFFSET				0x24
+#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK		0x000000FF
+
+static void iproc_rng200_restart(void __iomem *rng_base)
+{
+	uint32_t val;
+
+	/* Disable RBG */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_DISABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);
+
+	/* Clear all interrupt status */
+	iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);
+
+	/* Reset RNG and RBG */
+	val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
+	val &= ~RBG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RBG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE;
+	iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+	val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
+	val &= ~RNG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RNG_SOFT_RESET_RNG_SOFT_RESET_ACTIVE;
+	iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+	val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
+	val &= ~RNG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RNG_SOFT_RESET_RNG_SOFT_RESET_CLEAR;
+	iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+	val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
+	val &= ~RBG_SOFT_RESET_RNG_SOFT_RESET_MASK;
+	val |= RBG_SOFT_RESET_RNG_SOFT_RESET_CLEAR;
+	iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+	/* Enable RBG */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_ENABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);
+}
+
+static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max,
+			       bool wait)
+{
+	uint32_t status = 0;
+	uint32_t num_remaining = max;
+
+	#define MAX_RESETS_PER_READ	1
+	uint32_t num_resets = 0;
+
+	#define MAX_IDLE_TIME	(1 * HZ)
+	unsigned long idle_endtime = jiffies + MAX_IDLE_TIME;
+
+	/* Retrieve HW RNG registers base address. */
+	void __iomem *rng_base = (void __iomem *)rng->priv;
+
+	while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {
+
+		/* Is RNG sane? If not, reset it. */
+		status = ioread32(rng_base + RNG_INT_STATUS_OFFSET);
+		if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
+			RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {
+
+			if (num_resets >= MAX_RESETS_PER_READ)
+				return max - num_remaining;
+
+			iproc_rng200_restart(rng_base);
+			num_resets++;
+		}
+
+		/* Are there any random numbers available? */
+		if ((ioread32(rng_base + RNG_FIFO_COUNT_OFFSET) &
+				RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {
+
+			if (num_remaining >= sizeof(uint32_t)) {
+				/* Buffer has room to store entire word */
+				*(uint32_t *)buf = ioread32(rng_base +
+							RNG_FIFO_DATA_OFFSET);
+				buf += sizeof(uint32_t);
+				num_remaining -= sizeof(uint32_t);
+			} else {
+				/* Buffer can only store partial word */
+				uint32_t rnd_number = ioread32(rng_base +
+							RNG_FIFO_DATA_OFFSET);
+				memcpy(buf, &rnd_number, num_remaining);
+				buf += num_remaining;
+				num_remaining = 0;
+			}
+
+			/* Reset the IDLE timeout */
+			idle_endtime = jiffies + MAX_IDLE_TIME;
+		} else {
+			if (!wait)
+				/* Cannot wait, return immediately */
+				return max - num_remaining;
+
+			/* Can wait, give others chance to run */
+			cpu_relax();
+		}
+	}
+
+	return max - num_remaining;
+}
+
Quoted 8 lines

drivers/char/hw_random/iproc-rng200.c line 162

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+static struct hwrng iproc_rng200_ops = {
+	.name	= "iproc-rng200",
+	.read	= iproc_rng200_read,
+};

I would prefer if we allocated a driver-private structure that wraps hwrng instead of using statically allocated singleton as I wonder how it will behave if I bind/unbind the device several times.

ok, will revamp.

Quoted 14 lines

drivers/char/hw_random/iproc-rng200.c line 169

Quoted 8 lines
drivers/char/hw_random/iproc-rng200.c new file +7 -0
+
+static int iproc_rng200_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	void __iomem *rng_base = 0;
+	uint32_t val = 0;
+	int err = 0;

There is no need to initialize all variables as it suppressed "used but uninitialized" warnings from the compiler. Imagine someone adding a new init operation and when they handle failure they forget to adjust error code so it stays 0: for upper layers we'd signal success even though our device/driver are half-bound.

yes, will cleanup in other functions as well.

Quoted 11 lines

drivers/char/hw_random/iproc-rng200.c line 176

Quoted 8 lines
drivers/char/hw_random/iproc-rng200.c new file +7 -0
+
+	/* Map peripheral */
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(dev, "failed to get rng resources\n");
+		return -ENODEV;

If we have platform device but it is missing parts of necessary data it should be -EINVAL.

ok

Quoted 8 lines

drivers/char/hw_random/iproc-rng200.c line 180

Quoted 5 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+	}
+
+	rng_base = devm_ioremap_resource(dev, res);
+	if (!rng_base) {

devm_ioremap_resource() returns ERR_PTR-encoded result, you need to check with IS_ERR().

ok

Quoted 5 lines

drivers/char/hw_random/iproc-rng200.c line 182

Quoted 3 lines
drivers/char/hw_random/iproc-rng200.c new file +2 -0
+		dev_err(dev, "failed to remap rng regs\n");
+		return -ENODEV;
		return PTR_ERR(rng_base);

ok

Quoted 4 lines

drivers/char/hw_random/iproc-rng200.c line 183

Quoted 2 lines
drivers/char/hw_random/iproc-rng200.c new file +1 -0
+	}

There is no clock for RNG?

no additional clock needs to be enabled.

Quoted 11 lines

drivers/char/hw_random/iproc-rng200.c line 191

Quoted 9 lines
drivers/char/hw_random/iproc-rng200.c new file +8 -0
+
+	iproc_rng200_ops.priv = (unsigned long)rng_base;
+
+	/* Setup RNG. */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_ENABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);

That should be in [new] iproc_rng200_init().

ok, it looks like you are commenting based on what is done in omap-rng.
I can follow that model and move this into an init function.

Quoted 20 lines
Quoted 20 lines
drivers/char/hw_random/iproc-rng200.c new file +19 -0
+
+	/* Register driver */
+	err = hwrng_register(&iproc_rng200_ops);
+	if (err) {
+		dev_err(dev, "hwrng registration failed\n");
+		return err;
+	}
+	dev_info(dev, "hwrng registered\n");
+
+	return 0;
+}
+
+static int iproc_rng200_remove(struct platform_device *pdev)
+{
+	uint32_t val = 0;
+	void __iomem *rng_base = (void __iomem *)iproc_rng200_ops.priv;
+
+	/* Unregister driver */
+	hwrng_unregister(&iproc_rng200_ops);
Quoted 8 lines

drivers/char/hw_random/iproc-rng200.c line 216

Quoted 6 lines
drivers/char/hw_random/iproc-rng200.c new file +6 -0
+
+	/* Disable RNG hardware */
+	val = ioread32(rng_base + RNG_CTRL_OFFSET);
+	val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+	val |= RNG_CTRL_RNG_RBGEN_DISABLE;
+	iowrite32(val, rng_base + RNG_CTRL_OFFSET);

That should be in [new] iproc_rng200_cleanup().

ok, it looks like you are commenting based on what is done in omap-rng.

I can follow that model and move this into a cleanup function.

Quoted 9 lines

drivers/char/hw_random/iproc-rng200.c line 203

Quoted 5 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+
+	return 0;
+}
+

#ifdef CONFIG_OF

maybe?

driver will only be used with devicetree

Quoted 26 lines
Quoted 21 lines
drivers/char/hw_random/iproc-rng200.c new file +19 -1
+static const struct of_device_id iproc_rng200_of_match[] = {
+	{ .compatible = "brcm,iproc-rng200", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
+
+static struct platform_driver iproc_rng200_driver = {
+	.driver = {
+		.name = "iproc-rng200",
+		.of_match_table = iproc_rng200_of_match,
+	},
+	.probe		= iproc_rng200_probe,
+	.remove		= iproc_rng200_remove,
+};
+module_platform_driver(iproc_rng200_driver);
+
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver");
+MODULE_LICENSE("GPL v2");
--
Quoted 2 lines

2.3.0

Thanks.

maintainer
#216 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

In reply to Scott Branden
Quoted 5 lines · On Wednesday 25 February 2015 10:16:24 Scott Branden wrote:

This adds a driver for random number generator present on Broadcom IPROC devices.

The driver looks reasonable overall, I have just one question about something that sticks out:

Quoted 1 line
drivers/char/hw_random/iproc-rng200.c new file +1 -0
+	while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {

...

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+
+		/* Are there any random numbers available? */
+		if ((ioread32(rng_base + RNG_FIFO_COUNT_OFFSET) &
+				RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {

...

drivers/char/hw_random/iproc-rng200.c line 155

Quoted 10 lines
drivers/char/hw_random/iproc-rng200.c new file +10 -0
+		} else {
+			if (!wait)
+				/* Cannot wait, return immediately */
+				return max - num_remaining;
+
+			/* Can wait, give others chance to run */
+			cpu_relax();
+		}
+	}
+

It looks like you do a busy-loop around cpu_relax here if asked to wait. Is this intentional? I would normally expect either cond_resched() or some msleep() instead.

Arnd

author maintainer
#217 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Response inline.

Quoted 17 lines · Arnd Bergmann
Quoted 5 lines · On Wednesday 25 February 2015 10:16:24 Scott Branden wrote:

This adds a driver for random number generator present on Broadcom IPROC devices.

The driver looks reasonable overall, I have just one question about something that sticks out:

Quoted 1 line
drivers/char/hw_random/iproc-rng200.c new file +1 -0
+	while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {

...

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+
+		/* Are there any random numbers available? */
+		if ((ioread32(rng_base + RNG_FIFO_COUNT_OFFSET) &
+				RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {

...

Quoted 14 lines

drivers/char/hw_random/iproc-rng200.c line 155

Quoted 10 lines
drivers/char/hw_random/iproc-rng200.c new file +10 -0
+		} else {
+			if (!wait)
+				/* Cannot wait, return immediately */
+				return max - num_remaining;
+
+			/* Can wait, give others chance to run */
+			cpu_relax();
+		}
+	}
+

It looks like you do a busy-loop around cpu_relax here if asked to wait. Is this intentional? I would normally expect either cond_resched() or some msleep() instead.

This code was following examples of other open source drivers - bcm2835 and exynos both use cpu_relax. I'll have to look into this more to understand.

Quoted 3 lines

Arnd

maintainer
#218 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Quoted 35 lines · On Thursday 26 February 2015 11:37:20 Scott Branden wrote:

Response inline.

Quoted 17 lines · Arnd Bergmann
Quoted 5 lines · On Wednesday 25 February 2015 10:16:24 Scott Branden wrote:

This adds a driver for random number generator present on Broadcom IPROC devices.

The driver looks reasonable overall, I have just one question about something that sticks out:

Quoted 1 line

+ while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {

...

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+
+            /* Are there any random numbers available? */
+            if ((ioread32(rng_base + RNG_FIFO_COUNT_OFFSET) &
+                            RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {

...

Quoted 14 lines

drivers/char/hw_random/iproc-rng200.c line 155

Quoted 10 lines
drivers/char/hw_random/iproc-rng200.c new file +10 -0
+            } else {
+                    if (!wait)
+                            /* Cannot wait, return immediately */
+                            return max - num_remaining;
+
+                    /* Can wait, give others chance to run */
+                    cpu_relax();
+            }
+    }
+

It looks like you do a busy-loop around cpu_relax here if asked to wait. Is this intentional? I would normally expect either cond_resched() or some msleep() instead.

Quoted 4 lines

This code was following examples of other open source drivers - bcm2835 and exynos both use cpu_relax. I'll have to look into this more to understand.

The majority of the driver apparently use udelay(10) to wait, which is not much better but at least consistent. The cpu_relax() call probably gives better throughput.

I don't understand why none of the drivers actually attempts to msleep(), but that may be because the delay is much too long.

Can you find out what the expected latency is for new data to become available on your hardware?

Arnd

author maintainer
#219 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Hi Arnd,

Latency is 32 us for 32bits of data - commented inline. What delay call do you recommend in this case?

Quoted 45 lines · Arnd Bergmann
Quoted 35 lines · On Thursday 26 February 2015 11:37:20 Scott Branden wrote:

Response inline.

Quoted 17 lines · Arnd Bergmann
Quoted 5 lines · On Wednesday 25 February 2015 10:16:24 Scott Branden wrote:

This adds a driver for random number generator present on Broadcom IPROC devices.

The driver looks reasonable overall, I have just one question about something that sticks out:

Quoted 1 line

+ while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {

...

Quoted 4 lines
drivers/char/hw_random/iproc-rng200.c new file +4 -0
+
+            /* Are there any random numbers available? */
+            if ((ioread32(rng_base + RNG_FIFO_COUNT_OFFSET) &
+                            RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {

...

Quoted 14 lines

drivers/char/hw_random/iproc-rng200.c line 155

Quoted 10 lines
drivers/char/hw_random/iproc-rng200.c new file +10 -0
+            } else {
+                    if (!wait)
+                            /* Cannot wait, return immediately */
+                            return max - num_remaining;
+
+                    /* Can wait, give others chance to run */
+                    cpu_relax();
+            }
+    }
+

It looks like you do a busy-loop around cpu_relax here if asked to wait. Is this intentional? I would normally expect either cond_resched() or some msleep() instead.

Quoted 4 lines

This code was following examples of other open source drivers - bcm2835 and exynos both use cpu_relax. I'll have to look into this more to understand.

The majority of the driver apparently use udelay(10) to wait, which is not much better but at least consistent. The cpu_relax() call probably gives better throughput.

Quoted 5 lines

I don't understand why none of the drivers actually attempts to msleep(), but that may be because the delay is much too long.

Can you find out what the expected latency is for new data to become available on your hardware?

RNG generates at a nominal 1 Mbps. So to generate 32 bits of data takes approximately 32 us.

Quoted 3 lines

Arnd

maintainer
#220 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Quoted 12 lines · On Thursday 26 February 2015 14:26:02 Scott Branden wrote:
Quoted 11 lines · Arnd Bergmann
Quoted 6 lines · Arnd Bergmann
Quoted 1 line · On Wednesday 25 February 2015 10:16:24 Scott Branden wrote:

This code was following examples of other open source drivers - bcm2835 and exynos both use cpu_relax. I'll have to look into this more to understand.

The majority of the driver apparently use udelay(10) to wait, which is not much better but at least consistent. The cpu_relax() call probably gives better throughput.

Quoted 7 lines
Quoted 5 lines

I don't understand why none of the drivers actually attempts to msleep(), but that may be because the delay is much too long.

Can you find out what the expected latency is for new data to become available on your hardware?

RNG generates at a nominal 1 Mbps. So to generate 32 bits of data takes approximately 32 us.

The udelay(10) that the other drivers have seems about appropriate then, and we can independently think of a way to refine the interface. Please add a comment that explains the rate. Also, is there some kind of FIFO present in the hwrng device? If it can store close to 1ms work of data (1000 bits), you can just use an msleep(1) to wait for the pool to recover.

Another option would be to use usleep_range() with the exact amount of time to wait for, the lower bound being the minimum number of bytes asked for and the fifo size, the upper bound being the fifo size.

Arnd

author maintainer
#221 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Quoted 21 lines · Arnd Bergmann
Quoted 12 lines · On Thursday 26 February 2015 14:26:02 Scott Branden wrote:
Quoted 11 lines · Arnd Bergmann
Quoted 6 lines · Arnd Bergmann
Quoted 1 line · On Wednesday 25 February 2015 10:16:24 Scott Branden wrote:

This code was following examples of other open source drivers - bcm2835 and exynos both use cpu_relax. I'll have to look into this more to understand.

The majority of the driver apparently use udelay(10) to wait, which is not much better but at least consistent. The cpu_relax() call probably gives better throughput.

Quoted 7 lines
Quoted 5 lines

I don't understand why none of the drivers actually attempts to msleep(), but that may be because the delay is much too long.

Can you find out what the expected latency is for new data to become available on your hardware?

RNG generates at a nominal 1 Mbps. So to generate 32 bits of data takes approximately 32 us.

Quoted 6 lines

The udelay(10) that the other drivers have seems about appropriate then, and we can independently think of a way to refine the interface. Please add a comment that explains the rate. Also, is there some kind of FIFO present in the hwrng device? If it can store close to 1ms work of data (1000 bits), you can just use an msleep(1) to wait for the pool to recover.

FIFO is 512 bits. I will look as to whether we can live with 1/2 throughput.

Quoted 8 lines

Another option would be to use usleep_range() with the exact amount of time to wait for, the lower bound being the minimum number of bytes asked for and the fifo size, the upper bound being the fifo size.

Arnd

maintainer
#222 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Quoted 8 lines · On Saturday 28 February 2015 08:01:11 Scott Branden wrote:
Quoted 6 lines

The udelay(10) that the other drivers have seems about appropriate then, and we can independently think of a way to refine the interface. Please add a comment that explains the rate. Also, is there some kind of FIFO present in the hwrng device? If it can store close to 1ms work of data (1000 bits), you can just use an msleep(1) to wait for the pool to recover.

FIFO is 512 bits. I will look as to whether we can live with 1/2 throughput.

In that case, I think usleep_range(min(len * 8, 500), 500)) would be a good compromise: it waits at most until the fifo is full, but might return earlier if enough bits are available to fulfill the request.

Arnd

author maintainer
#223 lore raw

Re: [PATCH v2 2/2] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

Hi Arnd,

Thanks for the suggested change.

Quoted 7 lines · Arnd Bergmann
Quoted 6 lines · On Saturday 28 February 2015 08:01:11 Scott Branden wrote:
Quoted 6 lines

The udelay(10) that the other drivers have seems about appropriate then, and we can independently think of a way to refine the interface. Please add a comment that explains the rate. Also, is there some kind of FIFO present in the hwrng device? If it can store close to 1ms work of data (1000 bits), you can just use an msleep(1) to wait for the pool to recover.

Quoted 6 lines
Quoted 2 lines

FIFO is 512 bits. I will look as to whether we can live with 1/2 throughput.

In that case, I think usleep_range(min(len * 8, 500), 500)) would be a good compromise: it waits at most until the fifo is full, but might return earlier if enough bits are available to fulfill the request.

OK, will change in next version.

Quoted 3 lines

Arnd

maintainer
#224 lore raw

Re: [PATCH v2 0/2] Add support for Broadcom RNG200

In reply to Scott Branden
Quoted 5 lines · Scott Branden

This series of patchsets contains the Broadcom Random Number Generator driver and device tree binding documentation.

Changes from v1:
added \n to 2 dev_err messages

If you want this to go through the crypto tree please add a cc to linux-crypto at vger.kernel.org.

Thanks,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
author maintainer
#225 lore raw

v2 cover Add support for Broadcom keypad controller

In reply to a message not in the archive

This series of patchsets contains the Broadcom keypad controller driver and device tree binding documentation.

Changes from v1:
- updated dt documentation to remove to matrix-keymap.txt
- removed bcm_kp_remove as it is not necessary
- removed key-interrupt-trigger-type dt binding
- added bcm_kp_report_keys and call to process key registers

Scott Branden (2):
Input: bcm-keypad: add device tree bindings
Input: bcm-keypad: Add Broadcom keypad controller

 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++
 drivers/input/keyboard/Kconfig                     |  10 +
 drivers/input/keyboard/Makefile                    |   1 +
 drivers/input/keyboard/bcm-keypad.c                | 464 +++++++++++++++++++++
 4 files changed, 583 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
Signature · 1 line
2.3.0
author maintainer
#226 lore raw

PATCH v2 1/2 Input: bcm-keypad: add device tree bindings

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +108 -0
new file mode 100644
index 0000000..e16bb2d
@@ -0,0 +1,108 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- linux,keypad-no-autorepeat: An optional property indicating to
+  not enable autorepeat feature.
+
+- linux,keymap: The keymap for keys as described in the binding document
+  devicetree/bindings/input/matrix-keymap.txt.
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
Signature · 1 line
2.3.0
maintainer
#227 lore raw

Re: [PATCH v2 1/2] Input: bcm-keypad: add device tree bindings

Hi Scott,

Quoted 64 lines · Scott Branden

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +49 -0
new file mode 100644
index 0000000..e16bb2d
@@ -0,0 +1,108 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 59

Quoted 10 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +10 -0
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- linux,keypad-no-autorepeat: An optional property indicating to
+  not enable autorepeat feature.

Unfortunately we've accumulated a lot of bindings for turning autorepeat on or off, I would prefer if we standardize on what gpio-keys is doing and use "autorepeat" (no "linux,") for new drivers.

Thanks.

Signature · 1 line
Dmitry
author maintainer
#228 lore raw

Re: [PATCH v2 1/2] Input: bcm-keypad: add device tree bindings

Hi Dmitry,

Quoted 73 lines · Dmitry Torokhov

Hi Scott,

Quoted 70 lines · Scott Branden

Documents the Broadcom keypad controller device tree bindings.

---
  .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++++++++++++++++++
  1 file changed, 108 insertions(+)

create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +55 -0
new file mode 100644
index 0000000..e16bb2d
@@ -0,0 +1,108 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
Quoted 8 lines

Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt line 59

Quoted 4 lines
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +4 -0
+  If specified implies the keypad scan pull-up has been enabled.
+
+- linux,keypad-no-autorepeat: An optional property indicating to
+  not enable autorepeat feature.

Unfortunately we've accumulated a lot of bindings for turning autorepeat on or off, I would prefer if we standardize on what gpio-keys is doing and use "autorepeat" (no "linux,") for new drivers.

OK. I can change it.

Quoted 3 lines

Thanks.

author maintainer
#229 lore raw

PATCH v2 2/2 Input: bcm-keypad: Add Broadcom keypad controller

In reply to Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 464 ++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
 endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
 obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +464 -0

464 lines not on this page · raw message

Signature · 1 line
2.3.0
maintainer
#230 lore raw

Re: [PATCH v2 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Scott,

Mostly style nitpicks here...

Quoted 278 lines · Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 464 ++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
 endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
 obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +224 -0
new file mode 100644
index 0000000..f229ac0
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+#include <linux/stddef.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/memory.h>
+#include <linux/io.h>
+#include <linux/input/matrix_keypad.h>
+
+#define DEFAULT_CLK_HZ                  31250
+/* Repeat period (ms) */
+#define KEY_REPEAT_PERIOD               100
+/* First time press dly (ms) */
+#define KEY_REPEAT_DELAY                400
+#define MAX_ROWS                        8
+#define MAX_COLS                        8
+
+/* Register/field definitions */
+#define KPCR_OFFSET                          0x00000080
+#define KPCR_MODE                       0x00000002
+#define KPCR_MODE_SHIFT                 1
+#define KPCR_MODE_MASK                  1
+#define KPCR_ENABLE                     0x00000001
+#define KPCR_STATUSFILTERENABLE         0x00008000
+#define KPCR_STATUSFILTERTYPE_SHIFT          12
+#define KPCR_COLFILTERENABLE            0x00000800
+#define KPCR_COLFILTERTYPE_SHIFT             8
+#define KPCR_ROWWIDTH_SHIFT                  20
+#define KPCR_COLUMNWIDTH_SHIFT               16
+
+#define KPIOR_OFFSET                         0x00000084
+#define KPIOR_ROWOCONTRL_SHIFT               24
+#define KPIOR_ROWOCONTRL_MASK                0xFF000000
+#define KPIOR_COLUMNOCONTRL_SHIFT            16
+#define KPIOR_COLUMNOCONTRL_MASK             0x00FF0000
+#define KPIOR_COLUMN_IO_DATA_SHIFT           0
+
+#define KPEMR0_OFFSET                        0x00000090
+#define KPEMR1_OFFSET                        0x00000094
+#define KPEMR2_OFFSET                        0x00000098
+#define KPEMR3_OFFSET                        0x0000009C
+#define KPEMR_EDGETYPE_BOTH 3
+
+#define KPSSR0_OFFSET                        0x000000A0
+#define KPSSR1_OFFSET                        0x000000A4
+#define KPSSRN_OFFSET(reg_n)                 (KPSSR0_OFFSET + (4 * reg_n))
+#define KPIMR0_OFFSET                        0x000000B0
+#define KPIMR1_OFFSET                        0x000000B4
+#define KPICR0_OFFSET                        0x000000B8
+#define KPICR1_OFFSET                        0x000000BC
+#define KPICRN_OFFSET(reg_n)                 (KPICR0_OFFSET + (4 * reg_n))
+#define KPISR0_OFFSET                        0x000000C0
+#define KPISR1_OFFSET                        0x000000C4
+
+#define KPCR_STATUSFILTERTYPE_MAX 7
+#define KPCR_COLFILTERTYPE_MAX 7
+
+/* Macros to determine the row/column from a bit that is set in SSR0/1. */
+#define BIT_TO_ROW_SSRN(bit_nr, reg_n)  ((bit_nr >> 3) + (4 * reg_n))
+#define BIT_TO_COL(bit_nr)       (bit_nr % 8)
+
+/* Structure representing various run-time entities */
+struct bcm_kp {
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	struct input_dev *input_dev;
+	unsigned long last_state[2];
+	unsigned int n_rows;
+	unsigned int n_cols;
+	u32 kpcr;
+	u32 kpior;
+	u32 kpemr;
+	u32 imr0_val;
+	u32 imr1_val;
+};
+
+/*
+ * Returns the keycode from the input device keymap given the row and
+ * column.
+ */
+static inline int bcm_kp_get_keycode(struct bcm_kp *kp, int row, int col)
+{
+	unsigned int row_shift = get_count_order(kp->n_cols);
+	unsigned short *keymap = kp->input_dev->keycode;
+
+	return keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
+}
+
+static void bcm_kp_report_keys(struct bcm_kp *kp, int reg_num, int pull_mode)
+{
+	unsigned long state, change;
+	int bit_nr;
+	int key_press;
+	int row, col;
+	unsigned int keycode;
+
+	/* Clear interrupts */
+	writel(0xFFFFFFFF, kp->base + KPICRN_OFFSET(reg_num));
+
+	state = readl(kp->base + KPSSRN_OFFSET(reg_num));
+	change = kp->last_state[reg_num] ^ state;
+	kp->last_state[reg_num] = state;
+
+	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
+		key_press = state & BIT(bit_nr);
+		/* The meaning of SSR register depends on pull mode. */
+		key_press = pull_mode ? !key_press : key_press;
+		row = BIT_TO_ROW_SSRN(bit_nr, reg_num);
+		col = BIT_TO_COL(bit_nr);
+		keycode = bcm_kp_get_keycode(kp, row, col);
+		input_report_key(kp->input_dev, keycode, key_press);
+	}
+}
+
+static irqreturn_t bcm_kp_isr_thread(int irq, void *dev_id)
+{
+	struct bcm_kp *kp = dev_id;
+	int pull_mode = (kp->kpcr >> KPCR_MODE_SHIFT) & KPCR_MODE_MASK;
+	int reg_num;
+
+	for (reg_num = 0; reg_num <= 1; reg_num++)
+		bcm_kp_report_keys(kp, reg_num, pull_mode);
+
+	input_sync(kp->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm_kp_start(struct bcm_kp *kp)
+{
+	int error;
+
+	error = clk_prepare_enable(kp->clk);
+	if (error)
+		return error;
+
+	writel(kp->kpior, kp->base + KPIOR_OFFSET);
+
+	writel(kp->imr0_val, kp->base + KPIMR0_OFFSET);
+	writel(kp->imr1_val, kp->base + KPIMR1_OFFSET);
+
+	writel(kp->kpemr, kp->base + KPEMR0_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR1_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR2_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR3_OFFSET);
+
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	kp->last_state[0] = readl(kp->base + KPSSR0_OFFSET);
+	kp->last_state[0] = readl(kp->base + KPSSR1_OFFSET);
+
+	writel(kp->kpcr | KPCR_ENABLE, kp->base + KPCR_OFFSET);
+
+	return 0;
+}
+
+static void bcm_kp_stop(const struct bcm_kp *kp)
+{
+	u32 val;
+
+	val = readl(kp->base + KPCR_OFFSET);
+	val &= ~KPCR_ENABLE;
+	writel(0, kp->base + KPCR_OFFSET);
+	writel(0, kp->base + KPIMR0_OFFSET);
+	writel(0, kp->base + KPIMR1_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	clk_disable_unprepare(kp->clk);
+}
+
+static int bcm_kp_open(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	return bcm_kp_start(kp);
+}
+
+static void bcm_kp_close(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	bcm_kp_stop(kp);
+}
+
+static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp)
+{
+	struct device *dev = kp->input_dev->dev.parent;
+	struct device_node *np = dev->of_node;
+	int error;
+	unsigned int dt_val;
+	unsigned int i;
+
+	/* Initialize the KPCR Keypad Configuration Register */
+	kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE;
+
+	error = matrix_keypad_parse_of_params(dev, &kp->n_rows, &kp->n_cols);
+	if (error) {
+		dev_err(dev, "failed to parse kp params\n");

drivers/input/keyboard/bcm-keypad.c line 234

Quoted 10 lines
drivers/input/keyboard/bcm-keypad.c new file +10 -0
+		return error;
+	}
+	/* Set row width for the ASIC block. */
+	kp->kpcr |= (kp->n_rows - 1) << KPCR_ROWWIDTH_SHIFT;
+
+	/* Set column width for the ASIC block. */
+	kp->kpcr |= (kp->n_cols - 1) << KPCR_COLUMNWIDTH_SHIFT;
+
+	/* Configure the IMR registers */
+	{

Woudl prefer not having nested unnamed blocks in functions. If it deserves a separate block it deserves its own function.

drivers/input/keyboard/bcm-keypad.c line 240

Quoted 6 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+		unsigned int num_rows, col_mask, rows_set;
+
+		/* IMR registers contain interrupt enable bits for 8x8 matrix
+		 * IMR0 register format: <row3> <row2> <row1> <row0>
+		 * IMR1 register format: <row7> <row6> <row5> <row4>
+		 */

Multi-line comments are in form

/*
* Multi
* line
* comment
*/

Quoted 147 lines
drivers/input/keyboard/bcm-keypad.c new file +147 -0
+
+		col_mask = (1 << (kp->n_cols)) - 1;
+		num_rows = kp->n_rows;
+
+		/* Set column bits in rows 0 to 3 in IMR0 */
+		kp->imr0_val = col_mask;
+
+		rows_set = 1;
+		while ((--num_rows) && (rows_set++ < 4))
+			kp->imr0_val |= (kp->imr0_val << MAX_COLS);
+
+		/* Set column bits in rows 4 to 7 in IMR1 */
+		kp->imr1_val = 0;
+		if (num_rows) {
+			kp->imr1_val = col_mask;
+			while (--num_rows)
+				kp->imr1_val |= (kp->imr1_val << MAX_COLS);
+		}
+	}
+
+	/* Initialize the KPEMR Keypress Edge Mode Registers */
+	/* Trigger on both edges */
+	kp->kpemr = 0;
+	for (i = 0; i <= 30; i = i + 2)
+		kp->kpemr |= (KPEMR_EDGETYPE_BOTH << i);
+
+	/*
+	 * Obtain the Status filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "status-debounce-filter-period",
+		&dt_val);
+	if (dt_val > KPCR_STATUSFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Status filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_STATUSFILTERTYPE_SHIFT;
+
+
+	/*
+	 * Obtain the Column filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "col-debounce-filter-period",
+		&dt_val);
+
+	if (dt_val > KPCR_COLFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Column filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_COLFILTERTYPE_SHIFT;
+
+	/*
+	 * Determine between the row and column,
+	 * which should be configured as output.
+	 */
+	if (of_property_read_bool(np, "row-output-enabled")) {
+		/*
+		* Set RowOContrl or ColumnOContrl in KPIOR
+		* to the number of pins to drive as outputs
+		*/
+		kp->kpior = (((1 << kp->n_rows) - 1) <<
+				KPIOR_ROWOCONTRL_SHIFT);
+	} else {
+		kp->kpior = (((1 << kp->n_cols) - 1) <<
+				KPIOR_COLUMNOCONTRL_SHIFT);
+	}
+
+	/*
+	 * Determine if the scan pull up needs to be enabled
+	 */
+	if (of_property_read_bool(np, "pull-up-enabled"))
+		kp->kpcr |= KPCR_MODE;
+
+	dev_dbg(dev, "n_rows=%d n_col=%d kpcr=%x kpior=%x kpemr=%x\n",
+		kp->n_rows, kp->n_cols,
+		kp->kpcr, kp->kpior, kp->kpemr);
+
+	return 0;
+}
+
+
+static int bcm_kp_probe(struct platform_device *pdev)
+{
+	struct bcm_kp *kp;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int error;
+	bool repeat;
+
+	kp = devm_kzalloc(&pdev->dev, sizeof(*kp),
+				   GFP_KERNEL);
+	if (!kp)
+		return -ENOMEM;
+
+	input_dev = devm_input_allocate_device(&pdev->dev);
+	if (!input_dev) {
+		dev_err(&pdev->dev, "failed to allocate the input device\n");
+		return -ENOMEM;
+	}
+
+	__set_bit(EV_KEY, input_dev->evbit);
+
+	repeat = !of_property_read_bool(pdev->dev.of_node,
+					"linux,input-no-autorepeat");
+	if (repeat)
+		__set_bit(EV_REP, input_dev->evbit);
+
+	input_dev->name = pdev->name;
+	input_dev->phys = "keypad/input0";
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = bcm_kp_open;
+	input_dev->close = bcm_kp_close;
+
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+
+	input_set_drvdata(input_dev, kp);
+
+	kp->input_dev = input_dev;
+
+	platform_set_drvdata(pdev, kp);
+
+	error = bcm_kp_matrix_key_parse_dt(kp);
+	if (error)
+		return error;
+
+	error = matrix_keypad_build_keymap(NULL, NULL,
+					   kp->n_rows,
+					   kp->n_cols,
+					   NULL, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		return error;
+	}
+
+	/* Get the KEYPAD base address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Missing keypad base address resource\n");
+		return -ENODEV;
+	}
+

drivers/input/keyboard/bcm-keypad.c line 397

Quoted 10 lines
drivers/input/keyboard/bcm-keypad.c new file +10 -0
+	kp->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kp->base))
+		return PTR_ERR(kp->base);
+
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk))
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

If one branch has curly braces all other have to have them too.

Quoted 70 lines
drivers/input/keyboard/bcm-keypad.c new file +67 -0
+	else {
+		unsigned int desired_rate;
+		long actual_rate;
+
+		error = of_property_read_u32(pdev->dev.of_node,
+				"clock-frequency", &desired_rate);
+		if (error < 0)
+			desired_rate = DEFAULT_CLK_HZ;
+
+		actual_rate = clk_round_rate(kp->clk, desired_rate);
+		if (actual_rate <= 0)
+			return -EINVAL;
+
+		error = clk_set_rate(kp->clk, actual_rate);
+		if (error)
+			return -EINVAL;
+
+		error = clk_prepare_enable(kp->clk);
+		if (error)
+			return -EINVAL;
+	}
+
+	/* Put the kp into a known sane state */
+	bcm_kp_stop(kp);
+
+	kp->irq = platform_get_irq(pdev, 0);
+	if (kp->irq < 0) {
+		dev_err(&pdev->dev, "no IRQ specified\n");
+		return -EINVAL;
+	}
+
+	error = devm_request_threaded_irq(&pdev->dev, kp->irq, NULL,
+		bcm_kp_isr_thread,
+		IRQF_ONESHOT, pdev->name, kp);
+	if (error) {
+		dev_err(&pdev->dev, "failed to request IRQ\n");
+		return error;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register input device\n");
+		return error;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id bcm_kp_of_match[] = {
+	{ .compatible = "brcm,bcm-keypad" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bcm_kp_of_match);
+
+static struct platform_driver bcm_kp_device_driver = {
+	.probe		= bcm_kp_probe,
+	.driver		= {
+		.name	= "bcm-keypad",
+		.of_match_table = of_match_ptr(bcm_kp_of_match),
+	}
+};
+
+module_platform_driver(bcm_kp_device_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("BCM Keypad Driver");
+MODULE_LICENSE("GPL");
Signature · 1 line
2.3.0

Thanks!

Signature · 1 line
Dmitry
author maintainer
#231 lore raw

Re: [PATCH v2 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Quoted 288 lines · Dmitry Torokhov

Hi Scott,

Mostly style nitpicks here...

Quoted 283 lines · Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
  drivers/input/keyboard/Kconfig      |  10 +
  drivers/input/keyboard/Makefile     |   1 +
  drivers/input/keyboard/bcm-keypad.c | 464 ++++++++++++++++++++++++++++++++++++
  3 files changed, 475 insertions(+)

create mode 100644 drivers/input/keyboard/bcm-keypad.c

drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
  	  To compile this driver as a module, choose M here: the
  	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
  endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
  obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
  obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
  obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
  obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
  obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
  obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +229 -0
new file mode 100644
index 0000000..f229ac0
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+#include <linux/stddef.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/memory.h>
+#include <linux/io.h>
+#include <linux/input/matrix_keypad.h>
+
+#define DEFAULT_CLK_HZ                  31250
+/* Repeat period (ms) */
+#define KEY_REPEAT_PERIOD               100
+/* First time press dly (ms) */
+#define KEY_REPEAT_DELAY                400
+#define MAX_ROWS                        8
+#define MAX_COLS                        8
+
+/* Register/field definitions */
+#define KPCR_OFFSET                          0x00000080
+#define KPCR_MODE                       0x00000002
+#define KPCR_MODE_SHIFT                 1
+#define KPCR_MODE_MASK                  1
+#define KPCR_ENABLE                     0x00000001
+#define KPCR_STATUSFILTERENABLE         0x00008000
+#define KPCR_STATUSFILTERTYPE_SHIFT          12
+#define KPCR_COLFILTERENABLE            0x00000800
+#define KPCR_COLFILTERTYPE_SHIFT             8
+#define KPCR_ROWWIDTH_SHIFT                  20
+#define KPCR_COLUMNWIDTH_SHIFT               16
+
+#define KPIOR_OFFSET                         0x00000084
+#define KPIOR_ROWOCONTRL_SHIFT               24
+#define KPIOR_ROWOCONTRL_MASK                0xFF000000
+#define KPIOR_COLUMNOCONTRL_SHIFT            16
+#define KPIOR_COLUMNOCONTRL_MASK             0x00FF0000
+#define KPIOR_COLUMN_IO_DATA_SHIFT           0
+
+#define KPEMR0_OFFSET                        0x00000090
+#define KPEMR1_OFFSET                        0x00000094
+#define KPEMR2_OFFSET                        0x00000098
+#define KPEMR3_OFFSET                        0x0000009C
+#define KPEMR_EDGETYPE_BOTH 3
+
+#define KPSSR0_OFFSET                        0x000000A0
+#define KPSSR1_OFFSET                        0x000000A4
+#define KPSSRN_OFFSET(reg_n)                 (KPSSR0_OFFSET + (4 * reg_n))
+#define KPIMR0_OFFSET                        0x000000B0
+#define KPIMR1_OFFSET                        0x000000B4
+#define KPICR0_OFFSET                        0x000000B8
+#define KPICR1_OFFSET                        0x000000BC
+#define KPICRN_OFFSET(reg_n)                 (KPICR0_OFFSET + (4 * reg_n))
+#define KPISR0_OFFSET                        0x000000C0
+#define KPISR1_OFFSET                        0x000000C4
+
+#define KPCR_STATUSFILTERTYPE_MAX 7
+#define KPCR_COLFILTERTYPE_MAX 7
+
+/* Macros to determine the row/column from a bit that is set in SSR0/1. */
+#define BIT_TO_ROW_SSRN(bit_nr, reg_n)  ((bit_nr >> 3) + (4 * reg_n))
+#define BIT_TO_COL(bit_nr)       (bit_nr % 8)
+
+/* Structure representing various run-time entities */
+struct bcm_kp {
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	struct input_dev *input_dev;
+	unsigned long last_state[2];
+	unsigned int n_rows;
+	unsigned int n_cols;
+	u32 kpcr;
+	u32 kpior;
+	u32 kpemr;
+	u32 imr0_val;
+	u32 imr1_val;
+};
+
+/*
+ * Returns the keycode from the input device keymap given the row and
+ * column.
+ */
+static inline int bcm_kp_get_keycode(struct bcm_kp *kp, int row, int col)
+{
+	unsigned int row_shift = get_count_order(kp->n_cols);
+	unsigned short *keymap = kp->input_dev->keycode;
+
+	return keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
+}
+
+static void bcm_kp_report_keys(struct bcm_kp *kp, int reg_num, int pull_mode)
+{
+	unsigned long state, change;
+	int bit_nr;
+	int key_press;
+	int row, col;
+	unsigned int keycode;
+
+	/* Clear interrupts */
+	writel(0xFFFFFFFF, kp->base + KPICRN_OFFSET(reg_num));
+
+	state = readl(kp->base + KPSSRN_OFFSET(reg_num));
+	change = kp->last_state[reg_num] ^ state;
+	kp->last_state[reg_num] = state;
+
+	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
+		key_press = state & BIT(bit_nr);
+		/* The meaning of SSR register depends on pull mode. */
+		key_press = pull_mode ? !key_press : key_press;
+		row = BIT_TO_ROW_SSRN(bit_nr, reg_num);
+		col = BIT_TO_COL(bit_nr);
+		keycode = bcm_kp_get_keycode(kp, row, col);
+		input_report_key(kp->input_dev, keycode, key_press);
+	}
+}
+
+static irqreturn_t bcm_kp_isr_thread(int irq, void *dev_id)
+{
+	struct bcm_kp *kp = dev_id;
+	int pull_mode = (kp->kpcr >> KPCR_MODE_SHIFT) & KPCR_MODE_MASK;
+	int reg_num;
+
+	for (reg_num = 0; reg_num <= 1; reg_num++)
+		bcm_kp_report_keys(kp, reg_num, pull_mode);
+
+	input_sync(kp->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm_kp_start(struct bcm_kp *kp)
+{
+	int error;
+
+	error = clk_prepare_enable(kp->clk);
+	if (error)
+		return error;
+
+	writel(kp->kpior, kp->base + KPIOR_OFFSET);
+
+	writel(kp->imr0_val, kp->base + KPIMR0_OFFSET);
+	writel(kp->imr1_val, kp->base + KPIMR1_OFFSET);
+
+	writel(kp->kpemr, kp->base + KPEMR0_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR1_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR2_OFFSET);
+	writel(kp->kpemr, kp->base + KPEMR3_OFFSET);
+
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	kp->last_state[0] = readl(kp->base + KPSSR0_OFFSET);
+	kp->last_state[0] = readl(kp->base + KPSSR1_OFFSET);
+
+	writel(kp->kpcr | KPCR_ENABLE, kp->base + KPCR_OFFSET);
+
+	return 0;
+}
+
+static void bcm_kp_stop(const struct bcm_kp *kp)
+{
+	u32 val;
+
+	val = readl(kp->base + KPCR_OFFSET);
+	val &= ~KPCR_ENABLE;
+	writel(0, kp->base + KPCR_OFFSET);
+	writel(0, kp->base + KPIMR0_OFFSET);
+	writel(0, kp->base + KPIMR1_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
+	writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
+
+	clk_disable_unprepare(kp->clk);
+}
+
+static int bcm_kp_open(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	return bcm_kp_start(kp);
+}
+
+static void bcm_kp_close(struct input_dev *dev)
+{
+	struct bcm_kp *kp = input_get_drvdata(dev);
+
+	bcm_kp_stop(kp);
+}
+
+static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp)
+{
+	struct device *dev = kp->input_dev->dev.parent;
+	struct device_node *np = dev->of_node;
+	int error;
+	unsigned int dt_val;
+	unsigned int i;
+
+	/* Initialize the KPCR Keypad Configuration Register */
+	kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE;
+
+	error = matrix_keypad_parse_of_params(dev, &kp->n_rows, &kp->n_cols);
+	if (error) {
+		dev_err(dev, "failed to parse kp params\n");
+		return error;
+	}
+	/* Set row width for the ASIC block. */
+	kp->kpcr |= (kp->n_rows - 1) << KPCR_ROWWIDTH_SHIFT;
+
Quoted 8 lines

drivers/input/keyboard/bcm-keypad.c line 234

Quoted 5 lines
drivers/input/keyboard/bcm-keypad.c new file +5 -0
+	/* Set column width for the ASIC block. */
+	kp->kpcr |= (kp->n_cols - 1) << KPCR_COLUMNWIDTH_SHIFT;
+
+	/* Configure the IMR registers */
+	{

Woudl prefer not having nested unnamed blocks in functions. If it deserves a separate block it deserves its own function.

removed {

Quoted 10 lines

drivers/input/keyboard/bcm-keypad.c line 240

Quoted 7 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+		unsigned int num_rows, col_mask, rows_set;
+
+		/* IMR registers contain interrupt enable bits for 8x8 matrix
+		 * IMR0 register format: <row3> <row2> <row1> <row0>
+		 * IMR1 register format: <row7> <row6> <row5> <row4>
+		 */

Multi-line comments are in form

Quoted 6 lines

/*
* Multi
* line
* comment
*/

fixed

Quoted 151 lines
Quoted 151 lines
drivers/input/keyboard/bcm-keypad.c new file +151 -0
+
+		col_mask = (1 << (kp->n_cols)) - 1;
+		num_rows = kp->n_rows;
+
+		/* Set column bits in rows 0 to 3 in IMR0 */
+		kp->imr0_val = col_mask;
+
+		rows_set = 1;
+		while ((--num_rows) && (rows_set++ < 4))
+			kp->imr0_val |= (kp->imr0_val << MAX_COLS);
+
+		/* Set column bits in rows 4 to 7 in IMR1 */
+		kp->imr1_val = 0;
+		if (num_rows) {
+			kp->imr1_val = col_mask;
+			while (--num_rows)
+				kp->imr1_val |= (kp->imr1_val << MAX_COLS);
+		}
+	}
+
+	/* Initialize the KPEMR Keypress Edge Mode Registers */
+	/* Trigger on both edges */
+	kp->kpemr = 0;
+	for (i = 0; i <= 30; i = i + 2)
+		kp->kpemr |= (KPEMR_EDGETYPE_BOTH << i);
+
+	/*
+	 * Obtain the Status filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "status-debounce-filter-period",
+		&dt_val);
+	if (dt_val > KPCR_STATUSFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Status filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_STATUSFILTERTYPE_SHIFT;
+
+
+	/*
+	 * Obtain the Column filter debounce value and verify against the
+	 * possible values specified in the DT binding.
+	 */
+	of_property_read_u32(np, "col-debounce-filter-period",
+		&dt_val);
+
+	if (dt_val > KPCR_COLFILTERTYPE_MAX) {
+		dev_err(dev, "Invalid Column filter debounce value %d\n",
+			dt_val);
+		return -EINVAL;
+	}
+	kp->kpcr |= dt_val << KPCR_COLFILTERTYPE_SHIFT;
+
+	/*
+	 * Determine between the row and column,
+	 * which should be configured as output.
+	 */
+	if (of_property_read_bool(np, "row-output-enabled")) {
+		/*
+		* Set RowOContrl or ColumnOContrl in KPIOR
+		* to the number of pins to drive as outputs
+		*/
+		kp->kpior = (((1 << kp->n_rows) - 1) <<
+				KPIOR_ROWOCONTRL_SHIFT);
+	} else {
+		kp->kpior = (((1 << kp->n_cols) - 1) <<
+				KPIOR_COLUMNOCONTRL_SHIFT);
+	}
+
+	/*
+	 * Determine if the scan pull up needs to be enabled
+	 */
+	if (of_property_read_bool(np, "pull-up-enabled"))
+		kp->kpcr |= KPCR_MODE;
+
+	dev_dbg(dev, "n_rows=%d n_col=%d kpcr=%x kpior=%x kpemr=%x\n",
+		kp->n_rows, kp->n_cols,
+		kp->kpcr, kp->kpior, kp->kpemr);
+
+	return 0;
+}
+
+
+static int bcm_kp_probe(struct platform_device *pdev)
+{
+	struct bcm_kp *kp;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int error;
+	bool repeat;
+
+	kp = devm_kzalloc(&pdev->dev, sizeof(*kp),
+				   GFP_KERNEL);
+	if (!kp)
+		return -ENOMEM;
+
+	input_dev = devm_input_allocate_device(&pdev->dev);
+	if (!input_dev) {
+		dev_err(&pdev->dev, "failed to allocate the input device\n");
+		return -ENOMEM;
+	}
+
+	__set_bit(EV_KEY, input_dev->evbit);
+
+	repeat = !of_property_read_bool(pdev->dev.of_node,
+					"linux,input-no-autorepeat");
+	if (repeat)
+		__set_bit(EV_REP, input_dev->evbit);
+
+	input_dev->name = pdev->name;
+	input_dev->phys = "keypad/input0";
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = bcm_kp_open;
+	input_dev->close = bcm_kp_close;
+
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+
+	input_set_drvdata(input_dev, kp);
+
+	kp->input_dev = input_dev;
+
+	platform_set_drvdata(pdev, kp);
+
+	error = bcm_kp_matrix_key_parse_dt(kp);
+	if (error)
+		return error;
+
+	error = matrix_keypad_build_keymap(NULL, NULL,
+					   kp->n_rows,
+					   kp->n_cols,
+					   NULL, input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to build keymap\n");
+		return error;
+	}
+
+	/* Get the KEYPAD base address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Missing keypad base address resource\n");
+		return -ENODEV;
+	}
+
+	kp->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kp->base))
+		return PTR_ERR(kp->base);
+
Quoted 9 lines

drivers/input/keyboard/bcm-keypad.c line 397

Quoted 6 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk))
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

If one branch has curly braces all other have to have them too.

ok. would be nice for checkpatch to deal with such K&R concerns.

Quoted 73 lines
Quoted 68 lines
drivers/input/keyboard/bcm-keypad.c new file +67 -1
+	else {
+		unsigned int desired_rate;
+		long actual_rate;
+
+		error = of_property_read_u32(pdev->dev.of_node,
+				"clock-frequency", &desired_rate);
+		if (error < 0)
+			desired_rate = DEFAULT_CLK_HZ;
+
+		actual_rate = clk_round_rate(kp->clk, desired_rate);
+		if (actual_rate <= 0)
+			return -EINVAL;
+
+		error = clk_set_rate(kp->clk, actual_rate);
+		if (error)
+			return -EINVAL;
+
+		error = clk_prepare_enable(kp->clk);
+		if (error)
+			return -EINVAL;
+	}
+
+	/* Put the kp into a known sane state */
+	bcm_kp_stop(kp);
+
+	kp->irq = platform_get_irq(pdev, 0);
+	if (kp->irq < 0) {
+		dev_err(&pdev->dev, "no IRQ specified\n");
+		return -EINVAL;
+	}
+
+	error = devm_request_threaded_irq(&pdev->dev, kp->irq, NULL,
+		bcm_kp_isr_thread,
+		IRQF_ONESHOT, pdev->name, kp);
+	if (error) {
+		dev_err(&pdev->dev, "failed to request IRQ\n");
+		return error;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register input device\n");
+		return error;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id bcm_kp_of_match[] = {
+	{ .compatible = "brcm,bcm-keypad" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bcm_kp_of_match);
+
+static struct platform_driver bcm_kp_device_driver = {
+	.probe		= bcm_kp_probe,
+	.driver		= {
+		.name	= "bcm-keypad",
+		.of_match_table = of_match_ptr(bcm_kp_of_match),
+	}
+};
+
+module_platform_driver(bcm_kp_device_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("BCM Keypad Driver");
+MODULE_LICENSE("GPL");
--
Quoted 2 lines

2.3.0

Thanks!

#232 lore raw

Re: [PATCH v2 2/2] Input: bcm-keypad: Add Broadcom keypad controller

In reply to Scott Branden
Quoted 8 lines · Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

Quoted 8 lines
---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 464 ++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c

License nit follows.

drivers/input/keyboard/bcm-keypad.c line 6

Quoted 12 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
new file mode 100644
index 0000000..f229ac0
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.

This states that the license is GPL v2 only.

Quoted 6 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */

[...]

Quoted 1 line

+MODULE_LICENSE("GPL");

So you probably want

    MODULE_LICENSE("GPL v2");

Paul Bolle

author maintainer
#233 lore raw

Re: [PATCH v2 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Yes, will correct. Thanks.

Quoted 52 lines · Paul Bolle
Quoted 8 lines · Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

Quoted 8 lines
---
  drivers/input/keyboard/Kconfig      |  10 +
  drivers/input/keyboard/Makefile     |   1 +
  drivers/input/keyboard/bcm-keypad.c | 464 ++++++++++++++++++++++++++++++++++++
  3 files changed, 475 insertions(+)

create mode 100644 drivers/input/keyboard/bcm-keypad.c

License nit follows.

drivers/input/keyboard/bcm-keypad.c line 6

Quoted 12 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
new file mode 100644
index 0000000..f229ac0
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.

This states that the license is GPL v2 only.

Quoted 6 lines
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */

[...]

Quoted 1 line

+MODULE_LICENSE("GPL");

So you probably want

     MODULE_LICENSE("GPL v2");

Paul Bolle

author maintainer
#234 lore raw

v3 cover Add support for Broadcom keypad controller

In reply to a message not in the archive

This series of patchsets contains the Broadcom keypad controller driver and device tree binding documentation.

Changes from v2:
- changed binding to use autorepeat
- stylistic updates

Changes from v1:
- updated dt documentation to remove to matrix-keymap.txt
- removed bcm_kp_remove as it is not necessary
- removed key-interrupt-trigger-type dt binding
- added bcm_kp_report_keys and call to process key registers

Scott Branden (2):
Input: bcm-keypad: add device tree bindings
Input: bcm-keypad: Add Broadcom keypad controller

 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++
 drivers/input/keyboard/Kconfig                     |  10 +
 drivers/input/keyboard/Makefile                    |   1 +
 drivers/input/keyboard/bcm-keypad.c                | 463 +++++++++++++++++++++
 4 files changed, 582 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
Signature · 1 line
2.3.0
author maintainer
#235 lore raw

PATCH v3 1/2 Input: bcm-keypad: add device tree bindings

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +108 -0
new file mode 100644
index 0000000..b77f50b
@@ -0,0 +1,108 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- autorepeat: Boolean, Enable auto repeat feature of Linux input
+	  subsystem (optional).
+
+- linux,keymap: The keymap for keys as described in the binding document
+  devicetree/bindings/input/matrix-keymap.txt.
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
Signature · 1 line
2.3.0
author maintainer
#236 lore raw

PATCH v3 2/2 Input: bcm-keypad: Add Broadcom keypad controller

In reply to Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 463 ++++++++++++++++++++++++++++++++++++
 3 files changed, 474 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
 endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
 obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +463 -0

463 lines not on this page · raw message

Signature · 1 line
2.3.0
author maintainer
#237 lore raw

v4 cover Add support for Broadcom keypad controller

In reply to a message not in the archive

This series of patchsets contains the Broadcom keypad controller driver and device tree binding documentation.

Changes from v3:
- corrected GPL to GPL v2

Changes from v2:
- changed binding to use autorepeat
- stylistic updates

Changes from v1:
- updated dt documentation to remove to matrix-keymap.txt
- removed bcm_kp_remove as it is not necessary
- removed key-interrupt-trigger-type dt binding
- added bcm_kp_report_keys and call to process key registers

Scott Branden (2):
Input: bcm-keypad: add device tree bindings
Input: bcm-keypad: Add Broadcom keypad controller

 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++
 drivers/input/keyboard/Kconfig                     |  10 +
 drivers/input/keyboard/Makefile                    |   1 +
 drivers/input/keyboard/bcm-keypad.c                | 463 +++++++++++++++++++++
 4 files changed, 582 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
Signature · 1 line
2.3.0
author maintainer
#238 lore raw

PATCH v4 1/2 Input: bcm-keypad: add device tree bindings

Documents the Broadcom keypad controller device tree bindings.

---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +108 -0
new file mode 100644
index 0000000..b77f50b
@@ -0,0 +1,108 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- autorepeat: Boolean, Enable auto repeat feature of Linux input
+	  subsystem (optional).
+
+- linux,keymap: The keymap for keys as described in the binding document
+  devicetree/bindings/input/matrix-keymap.txt.
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
Signature · 1 line
2.3.0
maintainer
#239 lore raw

Re: [PATCH v4 1/2] Input: bcm-keypad: add device tree bindings

Quoted 4 lines · Scott Branden

Documents the Broadcom keypad controller device tree bindings.

I folded this into the patch adding the driver itself and queued for 4.1.

Thank you.

Quoted 122 lines
---
 .../devicetree/bindings/input/brcm,bcm-keypad.txt  | 108 +++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt
Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt new file +108 -0
new file mode 100644
index 0000000..b77f50b
@@ -0,0 +1,108 @@
+* Broadcom Keypad Controller device tree bindings
+
+Broadcom Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be "brcm,bcm-keypad"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu.
+
+Board Specific Properties:
+- keypad,num-rows: Number of row lines connected to the keypad
+  controller.
+
+- keypad,num-columns: Number of column lines connected to the
+  keypad controller.
+
+- col-debounce-filter-period: The debounce period for the Column filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- status-debounce-filter-period: The debounce period for the Status filter.
+
+	KEYPAD_DEBOUNCE_1_ms	=	0
+	KEYPAD_DEBOUNCE_2_ms	=	1
+	KEYPAD_DEBOUNCE_4_ms	=	2
+	KEYPAD_DEBOUNCE_8_ms	=	3
+	KEYPAD_DEBOUNCE_16_ms	=	4
+	KEYPAD_DEBOUNCE_32_ms	=	5
+	KEYPAD_DEBOUNCE_64_ms	=	6
+	KEYPAD_DEBOUNCE_128_ms	=	7
+
+- row-output-enabled: An optional property indicating whether the row or
+  column is being used as output. If specified the row is being used
+  as the output. Else defaults to column.
+
+- pull-up-enabled: An optional property indicating the Keypad scan mode.
+  If specified implies the keypad scan pull-up has been enabled.
+
+- autorepeat: Boolean, Enable auto repeat feature of Linux input
+	  subsystem (optional).
+
+- linux,keymap: The keymap for keys as described in the binding document
+  devicetree/bindings/input/matrix-keymap.txt.
+
+Example:
+#include "dt-bindings/input/input.h"
+
+/ {
+	keypad: keypad at 180ac000 {
+		/* Required SoC specific properties */
+		compatible = "brcm,bcm-keypad";
+
+		/* Required Board specific properties */
+		keypad,num-rows = <5>;
+		keypad,num-columns = <5>;
+		status = "okay";
+
+		linux,keymap = <MATRIX_KEY(0x00, 0x02, KEY_F) /* key_forward */
+		MATRIX_KEY(0x00, 0x03, KEY_HOME) /* key_home */
+		MATRIX_KEY(0x00, 0x04, KEY_M) /* key_message */
+		MATRIX_KEY(0x01, 0x00, KEY_A) /* key_contacts */
+		MATRIX_KEY(0x01, 0x01, KEY_1) /* key_1 */
+		MATRIX_KEY(0x01, 0x02, KEY_2) /* key_2 */
+		MATRIX_KEY(0x01, 0x03, KEY_3) /* key_3 */
+		MATRIX_KEY(0x01, 0x04, KEY_S) /* key_speaker */
+		MATRIX_KEY(0x02, 0x00, KEY_P) /* key_phone */
+		MATRIX_KEY(0x02, 0x01, KEY_4) /* key_4 */
+		MATRIX_KEY(0x02, 0x02, KEY_5) /* key_5 */
+		MATRIX_KEY(0x02, 0x03, KEY_6) /* key_6 */
+		MATRIX_KEY(0x02, 0x04, KEY_VOLUMEUP) /* key_vol_up */
+		MATRIX_KEY(0x03, 0x00, KEY_C) /* key_call_log */
+		MATRIX_KEY(0x03, 0x01, KEY_7) /* key_7 */
+		MATRIX_KEY(0x03, 0x02, KEY_8) /* key_8 */
+		MATRIX_KEY(0x03, 0x03, KEY_9) /* key_9 */
+		MATRIX_KEY(0x03, 0x04, KEY_VOLUMEDOWN) /* key_vol_down */
+		MATRIX_KEY(0x04, 0x00, KEY_H) /* key_headset */
+		MATRIX_KEY(0x04, 0x01, KEY_KPASTERISK) /* key_* */
+		MATRIX_KEY(0x04, 0x02, KEY_0) /* key_0 */
+		MATRIX_KEY(0x04, 0x03, KEY_GRAVE) /* key_# */
+		MATRIX_KEY(0x04, 0x04, KEY_MUTE) /* key_mute */
+		>;
+
+		/* Optional board specific properties */
+		col-debounce-filter-period = <5>;
+		row-output-enabled;
+		pull-up-enabled;
+
+	};
+};
Signature · 1 line
2.3.0
Signature · 1 line
Dmitry
author maintainer
#240 lore raw

PATCH v4 2/2 Input: bcm-keypad: Add Broadcom keypad controller

In reply to Scott Branden

Add driver for Broadcom's keypad controller.

Broadcom Keypad controller is used to interface a SoC with a matrix-type keypad device. The keypad controller supports multiple row and column lines. A key can be placed at each intersection of a unique row and a unique column. The keypad controller can sense a key-press and key-release and report the event using a interrupt to the cpu.

---
 drivers/input/keyboard/Kconfig      |  10 +
 drivers/input/keyboard/Makefile     |   1 +
 drivers/input/keyboard/bcm-keypad.c | 463 ++++++++++++++++++++++++++++++++++++
 3 files changed, 474 insertions(+)
 create mode 100644 drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/Kconfig +10 -0
index a5d9b3f..3a0c0f2 100644
@@ -676,4 +676,14 @@ config KEYBOARD_CAP11XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called cap11xx.
 
+config KEYBOARD_BCM
+	tristate "Broadcom keypad driver"
+	select INPUT_MATRIXKMAP
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to use Broadcom keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm-keypad.
+
 endif
drivers/input/keyboard/Makefile +1 -0
index febafa5..3cff8f6 100644
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CAP11XX)		+= cap11xx.o
 obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
drivers/input/keyboard/bcm-keypad.c new file +463 -0

463 lines not on this page · raw message

Signature · 1 line
2.3.0
maintainer
#241 lore raw

Re: [PATCH v4 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Scott,

drivers/input/keyboard/bcm-keypad.c line 395

Quoted 6 lines · Scott Branden
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk)) {
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

I was doing the final pass before applying and I think that this is not quite correct, as it does not handle -EPROBE_DEFER properly which is quite common. I think we should do something like this:

		error = PTR_ERR(kp->clk);
		if (error != -ENOENT) {
			if (error != -EPROBE_DEFER)
				dev_err(.. "Failed to get clock" ...);
			return error;
		}
		dev_dbg(... "No clock specified" ...);

No need to resubmit if you are OK with this, I can make the change locally.

Review

Quoted 2 lines
(quoted diff) +2 -0
+	}
+	else {

Checkpach should have warned you that it should have been "} else {"; I'll fix it up locally along with few other cosmetic changes and dropping a few extra headers.

Thanks.

Signature · 1 line
Dmitry
maintainer
#242 lore raw

Re: [PATCH v4 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Quoted 22 lines · Dmitry Torokhov

Hi Scott,

drivers/input/keyboard/bcm-keypad.c line 395

Quoted 6 lines · Scott Branden
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk)) {
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

I was doing the final pass before applying and I think that this is not quite correct, as it does not handle -EPROBE_DEFER properly which is quite common. I think we should do something like this:

		error = PTR_ERR(kp->clk);
		if (error != -ENOENT) {
			if (error != -EPROBE_DEFER)
				dev_err(.. "Failed to get clock" ...);
			return error;
		}
		dev_dbg(... "No clock specified" ...);
Quoted 2 lines

No need to resubmit if you are OK with this, I can make the change locally.

Hmm, also bcm_kp_start() and bcm_kp_stop() should check if kp->clk is valid before trying to enable/disable it.

Quoted 12 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+	}
+	else {

Checkpach should have warned you that it should have been "} else {"; I'll fix it up locally along with few other cosmetic changes and dropping a few extra headers.

Thanks.

Signature · 1 line
Dmitry
Signature · 1 line
Dmitry
author maintainer
#243 lore raw

Re: [PATCH v4 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Dmitry,

I don't see the need for a check of the clock in bcm_kp_start or stop. See comment below.

Quoted 23 lines · Dmitry Torokhov
Quoted 22 lines · Dmitry Torokhov

Hi Scott,

drivers/input/keyboard/bcm-keypad.c line 395

Quoted 6 lines · Scott Branden
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk)) {
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

I was doing the final pass before applying and I think that this is not quite correct, as it does not handle -EPROBE_DEFER properly which is quite common. I think we should do something like this:

		error = PTR_ERR(kp->clk);
		if (error != -ENOENT) {
			if (error != -EPROBE_DEFER)
				dev_err(.. "Failed to get clock" ...);
			return error;
		}
		dev_dbg(... "No clock specified" ...);
Quoted 6 lines
Quoted 2 lines

No need to resubmit if you are OK with this, I can make the change locally.

Hmm, also bcm_kp_start() and bcm_kp_stop() should check if kp->clk is valid before trying to enable/disable it.

I checked and other keyboard drivers do not check this. I return an error in bcm_kp_start if the clk enable fails. On stop, if the clk is not valid something is really, really wrong as well.

Quoted 13 lines
Quoted 12 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+	}
+	else {

Checkpach should have warned you that it should have been "} else {"; I'll fix it up locally along with few other cosmetic changes and dropping a few extra headers.

Thanks.

--
Dmitry

maintainer
#244 lore raw

Re: [PATCH v4 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Scott,

Quoted 32 lines · Scott Branden

Hi Dmitry,

I don't see the need for a check of the clock in bcm_kp_start or stop. See comment below.

Quoted 26 lines · Dmitry Torokhov
Quoted 24 lines · Dmitry Torokhov

Hi Scott,

drivers/input/keyboard/bcm-keypad.c line 395

Quoted 6 lines · Scott Branden
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk)) {
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

I was doing the final pass before applying and I think that this is not quite correct, as it does not handle -EPROBE_DEFER properly which is quite common. I think we should do something like this:

		error = PTR_ERR(kp->clk);
		if (error != -ENOENT) {
			if (error != -EPROBE_DEFER)
				dev_err(.. "Failed to get clock" ...);
			return error;
		}
		dev_dbg(... "No clock specified" ...);

No need to resubmit if you are OK with this, I can make the change locally.

Quoted 6 lines
Quoted 3 lines

Hmm, also bcm_kp_start() and bcm_kp_stop() should check if kp->clk is valid before trying to enable/disable it.

I checked and other keyboard drivers do not check this. I return an error in bcm_kp_start if the clk enable fails. On stop, if the clk is not valid something is really, really wrong as well.

The other drivers simply abort probe() if they can't get clock, you decided to allow probe() to finish and assume that clock is already enabled, leaving kp->clk == ERR_PTR(-ENOENT) in your version. If you try then calling clk_prepare_enable() with that pointer it is going to bomb, that is why I said you need to check pointer validity in bcm_kp_start() and bcm_kp_stop().

Thanks.

Signature · 1 line
Dmitry
author maintainer
#245 lore raw

Re: [PATCH v4 2/2] Input: bcm-keypad: Add Broadcom keypad controller

Hi Dmitry,

I understand what's missing now.

Thanks,
Scott

Quoted 18 lines · Dmitry Torokhov

Hi Scott,

Quoted 6 lines
Quoted 3 lines

Hmm, also bcm_kp_start() and bcm_kp_stop() should check if kp->clk is valid before trying to enable/disable it.

I checked and other keyboard drivers do not check this. I return an error in bcm_kp_start if the clk enable fails. On stop, if the clk is not valid something is really, really wrong as well.

The other drivers simply abort probe() if they can't get clock, you decided to allow probe() to finish and assume that clock is already enabled, leaving kp->clk == ERR_PTR(-ENOENT) in your version. If you try then calling clk_prepare_enable() with that pointer it is going to bomb, that is why I said you need to check pointer validity in bcm_kp_start() and bcm_kp_stop().

Thanks.

author maintainer
#246 lore raw

Re: [PATCH v4 2/2] Input: bcm-keypad: Add Broadcom keypad controller

In reply to Dmitry Torokhov

Hi Dmitry,

Yes, please improve the driver and make the local change.

Regards,
Scott

Quoted 23 lines · Dmitry Torokhov
Quoted 22 lines · Dmitry Torokhov

Hi Scott,

drivers/input/keyboard/bcm-keypad.c line 395

Quoted 6 lines · Scott Branden
drivers/input/keyboard/bcm-keypad.c new file +6 -0
+	/* Enable clock */
+
+	kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+	if (IS_ERR(kp->clk)) {
+		dev_info(&pdev->dev,
+			"No clock specified. Assuming it's enabled\n");

I was doing the final pass before applying and I think that this is not quite correct, as it does not handle -EPROBE_DEFER properly which is quite common. I think we should do something like this:

		error = PTR_ERR(kp->clk);
		if (error != -ENOENT) {
			if (error != -EPROBE_DEFER)
				dev_err(.. "Failed to get clock" ...);
			return error;
		}
		dev_dbg(... "No clock specified" ...);
Quoted 6 lines
Quoted 2 lines

No need to resubmit if you are OK with this, I can make the change locally.

Hmm, also bcm_kp_start() and bcm_kp_stop() should check if kp->clk is valid before trying to enable/disable it.

I am ok with these changes if you want to change locally.

Quoted 13 lines
Quoted 12 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+	}
+	else {

Checkpach should have warned you that it should have been "} else {"; I'll fix it up locally along with few other cosmetic changes and dropping a few extra headers.

Thanks.

--
Dmitry

author maintainer
#247 lore raw

v3 cover Add support for Broadcom RNG200

In reply to a message not in the archive

This series of patchsets contains the Broadcom Random Number Generator driver and device tree binding documentation.

Changes from v2:
added usleep_range instead of cpu_relax
add init and cleanup functions following new hwrng model

Changes from v1:
added \n to 2 dev_err messages

Scott Branden (2):
hwrng: iproc-rng200 - Add device tree bindings
hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

 .../bindings/hwrng/brcm,iproc-rng200.txt           |  12 +
 drivers/char/hw_random/Kconfig                     |  13 ++
 drivers/char/hw_random/Makefile                    |   1 +
 drivers/char/hw_random/iproc-rng200.c              | 254 +++++++++++++++++++++
 4 files changed, 280 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
Signature · 1 line
2.3.0
author maintainer
#248 lore raw

PATCH v3 1/2 hwrng: iproc-rng200 - Add device tree bindings

Documents the IPROC random number generator device tree bindings used in some Broadcom chipsets.

---
 .../devicetree/bindings/hwrng/brcm,iproc-rng200.txt          | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt new file +12 -0
new file mode 100644
index 0000000..e25a456
@@ -0,0 +1,12 @@
+HWRNG support for the iproc-rng200 driver
+
+Required properties:
+- compatible : "brcm,iproc-rng200"
+- reg : base address and size of control register block
+
+Example:
+
+rng {
+        compatible = "brcm,iproc-rng200";
+        reg = <0x18032000 0x28>;
+};
Signature · 1 line
2.3.0
author maintainer
#249 lore raw

PATCH v3 2/2 hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver

In reply to Scott Branden

This adds a driver for random number generator present on Broadcom IPROC devices.

---
 drivers/char/hw_random/Kconfig        |  13 ++
 drivers/char/hw_random/Makefile       |   1 +
 drivers/char/hw_random/iproc-rng200.c | 254 ++++++++++++++++++++++++++++++++++
 3 files changed, 268 insertions(+)
 create mode 100644 drivers/char/hw_random/iproc-rng200.c
drivers/char/hw_random/Kconfig +13 -0
index de57b38..f48cf11 100644
@@ -101,6 +101,19 @@ config HW_RANDOM_BCM2835
 
 	  If unsure, say Y.
 
+config HW_RANDOM_IPROC_RNG200
+	tristate "Broadcom iProc RNG200 support"
+	depends on ARCH_BCM_IPROC
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the RNG200
+	  hardware found on the Broadcom iProc SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-rng200
+
+	  If unsure, say Y.
+
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
 	depends on X86_32 && PCI
drivers/char/hw_random/Makefile +1 -0
index 0b4cd57..055bb01 100644
@@ -28,5 +28,6 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_EXYNOS)	+= exynos-rng.o
 obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
 obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
drivers/char/hw_random/iproc-rng200.c new file +254 -0

254 lines not on this page · raw message

Signature · 1 line
2.3.0
maintainer
#250 lore raw

Re: [PATCH v3 0/2] Add support for Broadcom RNG200

In reply to Scott Branden
Quoted 6 lines · Scott Branden

This series of patchsets contains the Broadcom Random Number Generator driver and device tree binding documentation.

Changes from v2:
added usleep_range instead of cpu_relax
add init and cleanup functions following new hwrng model

All applied. Thanks!

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
author maintainer
#251 lore raw

cover Add support for IPROC SDHCI controller

In reply to a message not in the archive

This series of patchsets contains the IPROC SDHCI driver used in a series of Broadcom SoCs
Quirks are also added to support this controller.

Corneliu Doban (1):
mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

Scott Branden (3):
mmc: sdhci: add quirk for ACMD23 broken
mmc: sdhci-iproc: add IPROC SDHCI driver
mmc: sdhci-iproc: add device tree bindings

 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   |  23 ++
 drivers/mmc/host/Kconfig                           |  14 ++
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/sdhci-iproc.c                     | 241 +++++++++++++++++++++
 drivers/mmc/host/sdhci.c                           |   7 +-
 include/linux/mmc/sdhci.h                          |   2 +
 6 files changed, 286 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
 create mode 100644 drivers/mmc/host/sdhci-iproc.c
Signature · 1 line
2.2.2
author maintainer
#252 lore raw

PATCH 1/4 mmc: sdhci: add quirk for ACMD23 broken

Add quirk to handle broken auto-CMD23.
Some controllers do not respond after the first auto-CMD23 is issued.

This allows CMD23 to still work (mandatory for the faster UHS-I mode) rather than disabling CMD23 entirely via SDHCI_QUIRK2_HOST_NO_CMD23.

Signed-off by: Corneliu Doban <[email protected]>

---
 drivers/mmc/host/sdhci.c  | 3 ++-
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +2 -1
index f1a488e..fcf78ab 100644
@@ -3085,7 +3085,8 @@ int sdhci_add_host(struct sdhci_host *host)
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
 	if ((host->version >= SDHCI_SPEC_300) &&
 	    ((host->flags & SDHCI_USE_ADMA) ||
-	     !(host->flags & SDHCI_USE_SDMA))) {
+	     !(host->flags & SDHCI_USE_SDMA)) &&
+	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
 		host->flags |= SDHCI_AUTO_CMD23;
 		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
 	} else {
include/linux/mmc/sdhci.h +2 -0
index f767a0d..a29e9bb 100644
@@ -106,6 +106,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD	(1<<10)
 /* Capability register bit-63 indicates HS400 support */
 #define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400		(1<<11)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<12)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
Signature · 1 line
2.2.2
author maintainer
#253 lore raw

PATCH 2/4 mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

In reply to Scott Branden

From: Corneliu Doban <[email protected]>

For CMD53 in block mode, the host does not need to stop the transfer, as it stops when the block count (present in CMD53) is reached.

---
 drivers/mmc/host/sdhci.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +3 -1
index fcf78ab..f35d413 100644
@@ -28,6 +28,7 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
 #include <linux/mmc/slot-gpio.h>
 
 #include "sdhci.h"
@@ -934,7 +935,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 		 * If we are sending CMD23, CMD12 never gets sent
 		 * on successful completion (so no Auto-CMD12).
 		 */
-		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
+		    (cmd->opcode != SD_IO_RW_EXTENDED))
 			mode |= SDHCI_TRNS_AUTO_CMD12;
 		else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
 			mode |= SDHCI_TRNS_AUTO_CMD23;
Signature · 1 line
2.2.2
author maintainer
#254 lore raw

PATCH 3/4 mmc: sdhci-iproc: add IPROC SDHCI driver

In reply to Scott Branden

Add IPROC SDHCI driver for IPROC family of Broadcom devices.

---
 drivers/mmc/host/Kconfig       |  14 +++
 drivers/mmc/host/Makefile      |   1 +
 drivers/mmc/host/sdhci-iproc.c | 241 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 256 insertions(+)
 create mode 100644 drivers/mmc/host/sdhci-iproc.c
drivers/mmc/host/Kconfig +14 -0
index 2d6fbdd..d6a2ff1 100644
@@ -292,6 +292,20 @@ config MMC_SDHCI_BCM2835
 
 	  If unsure, say N.
 
+config MMC_SDHCI_IPROC
+	tristate "SDHCI platform support for the iProc SD/MMC Controller"
+	depends on ARCH_BCM_IPROC || COMPILE_TEST
+	depends on MMC_SDHCI_PLTFM
+	default ARCH_BCM_IPROC
+	select MMC_SDHCI_IO_ACCESSORS
+	help
+	  This selects the iProc SD/MMC controller.
+
+	  If you have an IPROC platform with SD or MMC devices,
+	  say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_MOXART
 	tristate "MOXART SD/MMC Host Controller support"
 	depends on ARCH_MOXART && MMC
drivers/mmc/host/Makefile +1 -0
index f7b0a77..32f24bd 100644
@@ -70,6 +70,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)	+= sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)		+= sdhci-bcm2835.o
+obj-$(CONFIG_MMC_SDHCI_IPROC)		+= sdhci-iproc.o
 obj-$(CONFIG_MMC_SDHCI_MSM)		+= sdhci-msm.o
 obj-$(CONFIG_MMC_SDHCI_ST)		+= sdhci-st.o
 
drivers/mmc/host/sdhci-iproc.c new file +241 -0

241 lines not on this page · raw message

Signature · 1 line
2.2.2
author maintainer
#255 lore raw

PATCH 4/4 mmc: sdhci-iproc: add device tree bindings

In reply to Scott Branden

Add device tree binding documentation for IPROC SDHCI driver.

---
 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt new file +23 -0
new file mode 100644
index 0000000..72cc9cc
@@ -0,0 +1,23 @@
+Broadcom IPROC SDHCI controller
+
+This file documents differences between the core properties described
+by mmc.txt and the properties that represent the IPROC SDHCI controller.
+
+Required properties:
+- compatible : Should be "brcm,sdhci-iproc-cygnus".
+- clocks : The clock feeding the SDHCI controller.
+
+Optional properties:
+  - sdhci,auto-cmd12: specifies that controller should use auto CMD12.
+
+Example:
+
+sdhci0: sdhci at 0x18041000 {
+	compatible = "brcm,sdhci-iproc-cygnus";
+	reg = <0x18041000 0x100>;
+	interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
+	bus-width = <4>;
+	sdhci,auto-cmd12;
+	no-1-8-v;
+};
Signature · 1 line
2.2.2
Applied
#256 lore raw

Re: [PATCH RESEND 0/4] Add support for IPROC SDHCI controller

In reply to Scott Branden
Quoted 22 lines · Scott Branden

This series of patchsets contains the IPROC SDHCI driver used in a series of Broadcom SoCs
Quirks are also added to support this controller.

Corneliu Doban (1):
mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

Scott Branden (3):
mmc: sdhci: add quirk for ACMD23 broken
mmc: sdhci-iproc: add IPROC SDHCI driver
mmc: sdhci-iproc: add device tree bindings

 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   |  23 ++
 drivers/mmc/host/Kconfig                           |  14 ++
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/sdhci-iproc.c                     | 241 +++++++++++++++++++++
 drivers/mmc/host/sdhci.c                           |   7 +-
 include/linux/mmc/sdhci.h                          |   2 +
 6 files changed, 286 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
 create mode 100644 drivers/mmc/host/sdhci-iproc.c
Quoted 3 lines

--
2.2.2

Applied, thanks!

Actually, I needed to re-solve some conflicts and I switched to order of patch3 and patch4, to avoid checkpatch warnings. Just so you know.

Kind regards
Uffe

#257 lore raw

Re: [PATCH RESEND 0/4] Add support for IPROC SDHCI controller

Quoted 23 lines · Ulf Hansson
Quoted 22 lines · Scott Branden

This series of patchsets contains the IPROC SDHCI driver used in a series of Broadcom SoCs
Quirks are also added to support this controller.

Corneliu Doban (1):
mmc: sdhci: do not set AUTO_CMD12 for multi-block CMD53

Scott Branden (3):
mmc: sdhci: add quirk for ACMD23 broken
mmc: sdhci-iproc: add IPROC SDHCI driver
mmc: sdhci-iproc: add device tree bindings

 .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   |  23 ++
 drivers/mmc/host/Kconfig                           |  14 ++
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/sdhci-iproc.c                     | 241 +++++++++++++++++++++
 drivers/mmc/host/sdhci.c                           |   7 +-
 include/linux/mmc/sdhci.h                          |   2 +
 6 files changed, 286 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
 create mode 100644 drivers/mmc/host/sdhci-iproc.c
Quoted 8 lines
Quoted 3 lines

--
2.2.2

Applied, thanks!

Actually, I needed to re-solve some conflicts and I switched to order of patch3 and patch4, to avoid checkpatch warnings. Just so you know.

Thanks, patch 4 dropped from devicetree/next.

Signature · 1 line
Florian
author maintainer
#258 lore raw

PATCH 1/1 mmc: sdhci: fix card presence logic in sdhci_request function

In reply to a message not in the archive

The sdhci_request function should consider a non-removable device always present.
Call the correct logic already available in sdhci_do_get_cd function.

This fixes some logic paths where MMC requests are being made to non-removable devices that do not have the card detect pin connected on the hardware as it is non-removable.

---
 drivers/mmc/host/sdhci.c | 20 +++-----------------
 1 file changed, 3 insertions(+), 17 deletions(-)
drivers/mmc/host/sdhci.c +3 -17
index 0ad412a..bafc7ac 100644
@@ -56,6 +56,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 static int sdhci_pre_dma_transfer(struct sdhci_host *host,
 					struct mmc_data *data,
 					struct sdhci_host_next *next);
+static int sdhci_do_get_cd(struct sdhci_host *host);
 
 #ifdef CONFIG_PM
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -1356,7 +1357,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
 	sdhci_runtime_pm_get(host);
 
-	present = mmc_gpio_get_cd(host->mmc);
+	/* Firstly check card presence */
+	present = sdhci_do_get_cd(host);
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -1379,22 +1381,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
 	host->mrq = mrq;
 
-	/*
-	 * Firstly check card presence from cd-gpio.  The return could
-	 * be one of the following possibilities:
-	 *     negative: cd-gpio is not available
-	 *     zero: cd-gpio is used, and card is removed
-	 *     one: cd-gpio is used, and card is present
-	 */
-	if (present < 0) {
-		/* If polling, assume that the card is always present. */
-		if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-			present = 1;
-		else
-			present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-					SDHCI_CARD_PRESENT;
-	}
-
 	if (!present || host->flags & SDHCI_DEVICE_DEAD) {
 		host->mrq->cmd->error = -ENOMEDIUM;
 		tasklet_schedule(&host->finish_tasklet);
Signature · 1 line
2.3.0
Applied
#259 lore raw

Re: [PATCH] mmc: sdhci: fix card presence logic in sdhci_request function

Quoted 9 lines · Scott Branden

The sdhci_request function should consider a non-removable device always present.
Call the correct logic already available in sdhci_do_get_cd function.

This fixes some logic paths where MMC requests are being made to non-removable devices that do not have the card detect pin connected on the hardware as it is non-removable.

Thanks, applied!

Kind regards
Uffe

Quoted 52 lines
---
 drivers/mmc/host/sdhci.c | 20 +++-----------------
 1 file changed, 3 insertions(+), 17 deletions(-)
drivers/mmc/host/sdhci.c +3 -18
index 0ad412a..bafc7ac 100644
@@ -56,6 +56,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 static int sdhci_pre_dma_transfer(struct sdhci_host *host,
                                        struct mmc_data *data,
                                        struct sdhci_host_next *next);
+static int sdhci_do_get_cd(struct sdhci_host *host);
 
 #ifdef CONFIG_PM
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -1356,7 +1357,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        sdhci_runtime_pm_get(host);
 
-       present = mmc_gpio_get_cd(host->mmc);
+       /* Firstly check card presence */
+       present = sdhci_do_get_cd(host);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -1379,22 +1381,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        host->mrq = mrq;
 
-       /*
-        * Firstly check card presence from cd-gpio.  The return could
-        * be one of the following possibilities:
-        *     negative: cd-gpio is not available
-        *     zero: cd-gpio is used, and card is removed
-        *     one: cd-gpio is used, and card is present
-        */
-       if (present < 0) {
-               /* If polling, assume that the card is always present. */
-               if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-                       present = 1;
-               else
-                       present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                                       SDHCI_CARD_PRESENT;
-       }
-
        if (!present || host->flags & SDHCI_DEVICE_DEAD) {
                host->mrq->cmd->error = -ENOMEDIUM;
                tasklet_schedule(&host->finish_tasklet);
--

2.3.0

author maintainer
#260 lore raw

PATCH 1/1 wireless: rt2x00: add new rt2800usb device DWA 130

In reply to a message not in the archive

Add the USB Id to link the D-Link DWA 130 USB Wifi adapter to the rt2830 driver.

---
 drivers/net/wireless/rt2x00/rt2800usb.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/wireless/rt2x00/rt2800usb.c +1 -0
index 8444313..8694ddd 100644
@@ -1040,6 +1040,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x07d1, 0x3c17) },
 	{ USB_DEVICE(0x2001, 0x3317) },
 	{ USB_DEVICE(0x2001, 0x3c1b) },
+	{ USB_DEVICE(0x2001, 0x3c25) },
 	/* Draytek */
 	{ USB_DEVICE(0x07fa, 0x7712) },
 	/* DVICO */
Signature · 1 line
2.3.3
author maintainer
#262 lore raw

PATCH 1/1 ARM: amba: Increase number of IRQs

In reply to a message not in the archive

The current AMBA bus only allows up to 9 IRQs per device. This is incorrect, as in peripherals like PL330 can have up to 32 IRQs. Increase AMBA_NR_IRQS from 9 to 32.

---
 include/linux/amba/bus.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/amba/bus.h +1 -1
index 50fc668..475e090 100644
@@ -21,7 +21,7 @@
 #include <linux/resource.h>
 #include <linux/regulator/consumer.h>
 
-#define AMBA_NR_IRQS	9
+#define AMBA_NR_IRQS	32
 #define AMBA_CID	0xb105f00d
 #define CORESIGHT_CID	0xb105900d
 
Signature · 1 line
2.3.3
#263 lore raw

Re: [PATCH] ARM: amba: Increase number of IRQs

Quoted 3 lines · Scott Branden

The current AMBA bus only allows up to 9 IRQs per device. This is incorrect, as in peripherals like PL330 can have up to 32 IRQs. Increase AMBA_NR_IRQS from 9 to 32.

I'm quite certain that 32 will also be "incorrect" at some point in the future, so let's not use such language. Let's make this more neutral and say "This does not suit peripherals like the PL330 which can have up to 32 IRQs."

Thanks.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.
author maintainer
#264 lore raw

Re: [PATCH] ARM: amba: Increase number of IRQs

Hi Russell,

Quoted 9 lines · Russell King - ARM Linux
Quoted 3 lines · Scott Branden

The current AMBA bus only allows up to 9 IRQs per device. This is incorrect, as in peripherals like PL330 can have up to 32 IRQs. Increase AMBA_NR_IRQS from 9 to 32.

I'm quite certain that 32 will also be "incorrect" at some point in the future, so let's not use such language. Let's make this more neutral and say "This does not suit peripherals like the PL330 which can have up to 32 IRQs."

OK, I sent out a new patch with update commit message.

Thanks,
Scott

Quoted 3 lines

Thanks.

author maintainer
#265 lore raw

PATCH v2 1/1 ARM: amba: Increase number of IRQs

In reply to a message not in the archive

The current AMBA bus only allows up to 9 IRQs per device. This does not suit peripherals like PL330 which can have up to 32 IRQs. Increase AMBA_NR_IRQS from 9 to 32.

---
 include/linux/amba/bus.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/amba/bus.h +1 -1
index 50fc668..475e090 100644
@@ -21,7 +21,7 @@
 #include <linux/resource.h>
 #include <linux/regulator/consumer.h>
 
-#define AMBA_NR_IRQS	9
+#define AMBA_NR_IRQS	32
 #define AMBA_CID	0xb105f00d
 #define CORESIGHT_CID	0xb105900d
 
Signature · 1 line
2.3.3