Commit Graph

28 Commits

Author SHA1 Message Date
Hans de Goede 2153bbc12f pwm: lpss: Only set update bit if we are actually changing the settings
According to the datasheet the update bit must be set if the on-time-div
or the base-unit changes.

Now that we properly order device resume on Cherry Trail so that the GFX0
_PS0 method no longer exits with an error, we end up with a sequence of
events where we are writing the same values twice in a row.

First the _PS0 method restores the duty cycle of 0% the GPU driver set
on suspend and then the GPU driver first updates just the enabled bit in
the pwm_state from 0 to 1, causing us to write the same values again,
before restoring the pre-suspend duty-cycle in a separate pwm_apply call.

When writing the update bit the second time, without changing any of
the values the update bit clears immediately / instantly, instead of
staying 1 for a while as usual. After this the next setting of the update
bit seems to be ignored, causing the restoring of the pre-suspend
duty-cycle to not get applied. This makes the backlight come up with
a 0% dutycycle after suspend/resume.

Any further brightness changes after this do work.

This commit moves the setting of the update bit into pwm_lpss_prepare()
and only sets the bit if we have actually changed any of the values.

This avoids the setting of the update bit the second time we configure
the PWM to 0% dutycycle, this fixes the backlight coming up with 0%
duty-cycle after a suspend/resume.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2018-10-16 13:16:15 +02:00
Hans de Goede 280fec4c3a pwm: lpss: Add get_state callback
Add a get_state callback so that the initial state correctly reflects
the actual hardware state.

Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2018-10-12 12:33:02 +02:00
Hans de Goede 42885551ce pwm: lpss: Release runtime-pm reference from the driver's remove callback
For each pwm output which gets enabled through pwm_lpss_apply(), we do a
pm_runtime_get_sync().

This commit adds pm_runtime_put() calls to pwm_lpss_remove() to balance
these when the driver gets removed with some of the outputs still enabled.

Fixes: f080be27d7 ("pwm: lpss: Add support for runtime PM")
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2018-10-12 12:32:12 +02:00
Hans de Goede 9dc419b6c7 pwm: lpss: Move struct pwm_lpss_chip definition to the header file
Move struct pwm_lpss_chip definition from pwm-lpss.c to pwm-lpss.h,
so that the pci/platform drivers can access the info member
(struct pwm_lpss_boardinfo *).

This is a preparation patch for adding platform specific quirks, which
the drivers need access to, to pwm_lpss_boardinfo.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2018-10-12 12:31:01 +02:00
Hans de Goede 1d375b58c1 pwm: lpss: platform: Save/restore the ctrl register over a suspend/resume
On some devices the contents of the ctrl register get lost over a
suspend/resume and the PWM comes back up disabled after the resume.

This is seen on some Bay Trail devices with the PWM in ACPI enumerated
mode, so it shows up as a platform device instead of a PCI device.

If we still think it is enabled and then try to change the duty-cycle
after this, we end up with a "PWM_SW_UPDATE was not cleared" error and
the PWM is stuck in that state from then on.

This commit adds suspend and resume pm callbacks to the pwm-lpss-platform
code, which save/restore the ctrl register over a suspend/resume, fixing
this.

Note that:

1) There is no need to do this over a runtime suspend, since we
only runtime suspend when disabled and then we properly set the enable
bit and reprogram the timings when we re-enable the PWM.

2) This may be happening on more systems then we realize, but has been
covered up sofar by a bug in the acpi-lpss.c code which was save/restoring
the regular device registers instead of the lpss private registers due to
lpss_device_desc.prv_offset not being set. This is fixed by a later patch
in this series.

Cc: stable@vger.kernel.org
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2018-06-06 10:00:39 +02:00
Hans de Goede b997e3edca pwm: lpss: Set enable-bit before waiting for update-bit to go low
At least on cherrytrail, the update bit will never go low when the
enabled bit is not set.

This causes the backlight on my cube iwork8 air tablet to never turn on
again after being turned off because in the pwm_lpss_apply enable path
pwm_lpss_update will fail causing an error exit and the enable-bit to
never get set. Any following pwm_lpss_apply calls will fail the
pwm_lpss_is_updating check.

Since the docs say that the update bit should be set before the
enable-bit, split pwm_lpss_update into setting the update-bit and
pwm_lpss_wait_for_update, and move the pwm_lpss_wait_for_update call
in the enable path to after setting the enable-bit.

Fixes: 10d56a4 ("pwm: lpss: Avoid reconfiguring while UPDATE bit...")
Cc: Ilkka Koskinen <ilkka.koskinen@intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2017-04-06 14:48:14 +02:00
Andy Shevchenko 9900073cf5 pwm: lpss: Do not export board infos for different PWM types
The PWM LPSS probe drivers just pass a pointer to the exported board
info structures to pwm_lpss_probe() based on device PCI or ACPI ID.

In order to remove the knowledge of specific devices from library part of
the driver and reduce noise in exported namespace just duplicate the
board info structures and stop exporting them.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2017-01-30 08:16:55 +01:00
Ilkka Koskinen 10d56a4cb1 pwm: lpss: Avoid reconfiguring while UPDATE bit is still enabled
PWM Configuration register has SW_UPDATE bit that is set when a new
configuration is written to the register. The bit is automatically
cleared at the start of the next output cycle by the IP block.

If one writes a new configuration to the register while it still has
the bit enabled, PWM may freeze. That is, while one can still write
to the register, it won't have an effect. Thus, we try to sleep long
enough that the bit gets cleared and make sure the bit is not
enabled while we update the configuration.

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Richard Griffiths <richard.a.griffiths@intel.com>
Signed-off-by: Ilkka Koskinen <ilkka.koskinen@intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2017-01-30 08:15:12 +01:00
Andy Shevchenko b14e8ceff0 pwm: lpss: Switch to new atomic API
Instead of doing things separately, which is not so reliable on some platforms,
switch the driver to use new atomic API, i.e. ->apply() callback.

The change has been tested on Intel platforms such as Broxton, BayTrail, and
Merrifield.

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2017-01-30 08:13:55 +01:00
Andy Shevchenko b5c050c719 pwm: lpss: Allow duty cycle to be 0
A duty cycle is represented by values [0..<period>] which reflects [0%..100%].
0% of the duty cycle means always off (logical "0") on output. Allow this in
the driver.

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2017-01-30 08:13:39 +01:00
Andy Shevchenko 684309e504 pwm: lpss: Avoid potential overflow of base_unit
The resolution of base_unit is derived from base_unit_bits and thus must be
equal to (2^base_unit_bits - 1). Otherwise frequency and therefore base_unit
might potentially overflow.

Prevent the above by substracting 1 in all cases where base_unit_bits or
derivative is used.

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2017-01-30 08:13:19 +01:00
Andy Shevchenko d9cd4a7369 pwm: lpss: Move clk_rate check to ->probe()
There is no need to check each time if the clk_rate defined or not when we call
pwm_lpss_config(). Move the check to ->probe() instead.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2016-07-11 12:49:24 +02:00
Mika Westerberg ab248b6039 pwm: lpss: Prevent on_time_div overflow on lower frequencies
If duty_ns is large enough multiplying it by 255 overflows and results
wrong duty cycle value being programmed. For example with 10ms duty when
period is 20ms (50%) we get

  255 * 10000000 / 20000000 = -87

because 255 * 10000000 overlows int. Whereas correct value should be

  255 * 10000000 / 20000000 = 127

Fix this by using unsigned long long as type for on_time_div and changing
integer literals to use proper type annotation.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2016-07-11 12:07:24 +02:00
Dan O'Donovan e5ca42458b pwm: lpss: Fix base_unit calculation for PWM frequency
The base_unit calculation applies an offset of 0x2 which adds
significant error for lower frequencies and doesn't appear to be
warranted - rounding the division result gives a correct value.

Also, the upper limit check for base_unit is off-by-one; the upper
nibble of base_unit is invalid if >=128 according to the Table 88
in the Z8000 Processor Series Datasheet Volume 1 (Rev. 2).

Verified on UP Board (Cherry Trail) and Minnowboard Max (Bay Trail).

Signed-off-by: Dan O'Donovan <dan@emutex.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2016-07-11 12:07:23 +02:00
Mika Westerberg 37670676a1 pwm: lpss: Rework the sequence of programming PWM_SW_UPDATE
Setting of PWM_SW_UPDATE is bit different in Intel Broxton compared to the
previous generation SoCs. Previously it was OK to set the bit many times
(from userspace via sysfs for example) before the PWM is actually enabled.

Starting from Intel Broxton it seems that we must set PWM_SW_UPDATE only
once before the PWM is enabled. Otherwise it is possible that the PWM does
not start properly.

Change the sequence of how PWM_SW_UPDATE is programmed so that we only set
it in pwm_lpss_config() when the PWM is already enabled. The initial
setting of PWM_SW_UPDATE will be done when PWM gets enabled. This should
make the driver work with the previous generation Intel SoCs and Broxton.

Add also small delay after the bit is set to let the hardware propagate it
properly.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2015-12-16 16:52:09 +01:00
qipeng.zha 883e4d070f pwm: lpss: Update PWM setting for Broxton
For Broxton PWM controller, base unit is defined as 8-bit integer
and 14-bit fraction, so need to update base unit setting to output
wave with right frequency.

Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2015-12-16 16:45:38 +01:00
Mika Westerberg c7b91b33cf pwm: lpss: Remove ->free() callback
The LPSS PWM driver calls pwm_lpss_disable() when the PWM device is
released (for example unexported from sysfs). This in turn calls
pm_runtime_put() which makes runtime PM count to be unbalanced if the
device has not been enabled at this point.

This is easy to reproduce:

  # cd /sys/class/pwm/pwmchip0
  # echo 0 > export
  # echo 0 > unexport

The count is unbalanced and prevents the PWM device from being powered on
next time.

Fix this by removing ->free() callback. There are no resources to be
released anyway.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2015-12-16 16:31:27 +01:00
Qipeng Zha f080be27d7 pwm: lpss: Add support for runtime PM
To be able to save some power when PWM is not in use, add support for
runtime PM for this driver. This also allows the platform to transition to
low power S0ix states when the system is idle.

Signed-off-by: Huiquan Zhong <huiquan.zhong@intel.com>
Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2015-11-06 14:34:13 +01:00
Mika Westerberg 87219cb47e pwm: lpss: Support all four PWMs on Intel Broxton
Intel Broxton has similar PWM than Intel Braswell but instead of one it has
four PWMs included in one PCI/ACPI device. This patch adds support for all
the four PWMs and changes the PCI part of the driver to use
'pwm_lpss_bxt_info' instead.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2015-11-06 14:26:28 +01:00
Mika Westerberg 4e11f5acb2 pwm: lpss: Add support for multiple PWMs
New Intel SoCs such as Broxton will have four PWMs per PCI (or ACPI)
device. Each PWM has 1k of register space allocated from the parent device.
Add support for this.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2015-11-06 14:26:27 +01:00
Julia Lawall b2b7adeb21 pwm: lpss: use c99 initializers in structures
Use c99 initializers for structures.

A simplified version of the semantic match that finds this problem is as
follows: (http://coccinelle.lip6.fr/)

// <smpl>
@decl@
identifier i1,fld;
type T;
field list[n] fs;
@@

struct i1 {
 fs
 T fld;
 ...};

@bad@
identifier decl.i1,i2;
expression e;
initializer list[decl.n] is;
@@

struct i1 i2 = { is,
+ .fld = e
- e
 ,...};
// </smpl>

Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
[thierry.reding: rebased and applied same fix for Braswell]
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-08-25 11:45:34 +02:00
Thierry Reding e0c86a3b63 pwm: lpss: Fix build failure on PowerPC
An x86 build seems to pull in the linux/io.h include indirectly. On
PowerPC that doesn't happen and the build breaks due to the readl() and
writel() functions not being declared. Fix this by explicitly including
linux/io.h.

Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-08-23 00:25:52 +02:00
Andy Shevchenko c558e39e14 pwm: lpss: Properly split driver to parts
The driver consists of core, PCI, and platform parts. It would be better
to split them into separate files.

The platform driver is now called pwm-lpss-platform. Thus, previously
set CONFIG_PWM_LPSS=m is not enough to build it. But we are on the safe
side since it seems no one from outside Intel is using it for now.

While here, move to use macros module_pci_driver() and
module_platform_driver().

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Alan Cox <alan@linux.intel.com>
[thierry.reding: change select to depends on PWM_LPSS, cleanup]
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-08-23 00:25:47 +02:00
Alan Cox 373c57829a pwm: lpss: Add ACPI and PCI IDs for Intel Braswell
This is pretty much the same as Baytrail PWM. Only difference is that the
input clock runs on different frequency.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-08-22 11:52:30 +02:00
Heikki Krogerus 65accd8738 pwm: lpss: remove dependency on clk framework
Unlike other Intel LPSS devices, the PWM does not have the
clock dividers or the gate. All we get from the clock is the
rate. Since PCI case uses the driver data to get the rate,
we can drop the clk and use the same data also in case of
ACPI. The frequency is the same.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Chew, Chiau Ee <chiau.ee.chew@intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-08-07 13:18:03 +02:00
Thierry Reding 89c0339e0a pwm: lpss: Fix const qualifier and sparse warnings
Fixes the following warnings reported by the 0-DAY kernel build testing
backend:

   drivers/pwm/pwm-lpss.c: In function 'pwm_lpss_probe_pci':
>> drivers/pwm/pwm-lpss.c:192:2: warning: passing argument 3 of 'pwm_lpss_probe' discards 'const' qualifier from pointer target type [enabled by default]
     lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info);
     ^
   drivers/pwm/pwm-lpss.c:130:30: note: expected 'struct pwm_lpss_boardinfo *' but argument is of type 'const struct pwm_lpss_boardinfo *'
    static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev,
                                 ^
>> drivers/pwm/pwm-lpss.c:143:28: sparse: incorrect type in return expression (different address spaces)
   drivers/pwm/pwm-lpss.c:143:28:    expected struct pwm_lpss_chip *
   drivers/pwm/pwm-lpss.c:143:28:    got void [noderef] <asn:2>*regs
>> drivers/pwm/pwm-lpss.c:192:63: sparse: incorrect type in argument 3 (different modifiers)
   drivers/pwm/pwm-lpss.c:192:63:    expected struct pwm_lpss_boardinfo *info
   drivers/pwm/pwm-lpss.c:192:63:    got struct pwm_lpss_boardinfo const *[assigned] info
   drivers/pwm/pwm-lpss.c: In function 'pwm_lpss_probe_pci':
   drivers/pwm/pwm-lpss.c:192:2: warning: passing argument 3 of 'pwm_lpss_probe' discards 'const' qualifier from pointer target type [enabled by default]
     lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info);
     ^
   drivers/pwm/pwm-lpss.c:130:30: note: expected 'struct pwm_lpss_boardinfo *' but argument is of type 'const struct pwm_lpss_boardinfo *'
    static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev,
                                 ^

Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-05-07 10:27:57 +02:00
Alan Cox 093e00bb3f pwm: lpss: Add support for PCI devices
Not all systems enumerate the PWM devices via ACPI. They can also be
exposed via the PCI interface.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Chew, Chiau Ee <chiau.ee.chew@intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-04-28 13:47:03 +02:00
Mika Westerberg d16a5aa9e8 pwm: add support for Intel Low Power Subsystem PWM
Add support for Intel Low Power I/O subsystem PWM controllers found on
Intel BayTrail SoC.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Chew, Kean Ho <kean.ho.chew@intel.com>
Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
Signed-off-by: Chew, Chiau Ee <chiau.ee.chew@intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2014-04-01 12:03:40 +02:00