Compare commits

...

6 Commits

Author SHA1 Message Date
Phil Elwell
d98b3e2227 pwm: rp1: Correct period off-by-1 error
Correct the set_period method to pass (period - 1), as required by the
PIO state machine.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
2025-11-14 17:46:47 +00:00
Phil Elwell
776d6652f7 pwm: rp1: Silently correct illegal values
Remove the need for the user to know the limitations of this PWM
implementation by adjusting configuration requests to be the closest
acceptable value. Add a get_state method so that the actual values can
be queried.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
2025-11-14 17:46:47 +00:00
Phil Elwell
a6dc5bf29f mmc: bcm2835: Relax the 50MHz overclock check
EMMC clock speeds are based around divisions of 52Mhz, not the 50MHz
used by SD. As such, relax the "full speed" check (intended to stop
any overclock whenever an operation has to be retried) so that any
requested speed of 50MHz or higher will be overclocked.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
2025-11-14 17:46:47 +00:00
Phil Elwell
490f576bc0 mmc: bcm2835-mmc: Relax the 50MHz overclock check
EMMC clock speeds are based around divisions of 52Mhz, not the 50MHz
used by SD. As such, relax the "full speed" check (intended to stop
any overclock whenever an operation has to be retried) so that any
requested speed of 50MHz or higher will be overclocked.

See: https://github.com/raspberrypi/linux/issues/7120

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
2025-11-14 17:46:46 +00:00
Naushir Patuck
b923b354c0 drivers: i2c: imx708: Use pm_runtime_use_autosuspend()
Switch the power management in the imx708 device driver to use auto-
suspend with a 5s timeout.

This improves mode switching time that avoids additional regulator
switch-on delays and common register I2C writes.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
2025-11-14 17:46:46 +00:00
Phil Elwell
19a2aa9921 dma-mapping: MMIO mappings still need phys_to_dma
The new concept of MMIO DMA addresses is used to indicate things with
fixed addresses - hardware registers, not movable pages. As such it is
reasonable to bypass the SWIOTLB mapping logic, but not any CPU<->DMA
address translation that has been configured by Device Tree. Doing so
will break any drives using (possibly indirectly) dma_map_resource
for register addresses where ther is a non-identity mapping between
CPU and DMA addresses. A good example of this is the SDHOST MMC
interface on BCM283x SoCs.

Fix the bug by reinstating the phys_to_dma call in the MMIO code path.

N.B. The upstream SDHOST driver (drivers/mmc/host/bcm2835.c) is not
affected by this bug because it pulls bus/DMA addresses directly out
of Device Tree.

See: https://github.com/raspberrypi/linux/issues/7136
Fixes: e53d29f957 ("dma-mapping: convert dma_direct_*map_page to be phys_addr_t based")
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
2025-11-14 16:57:55 +00:00
5 changed files with 47 additions and 27 deletions

View File

@@ -1236,7 +1236,8 @@ static int imx708_set_ctrl(struct v4l2_ctrl *ctrl)
break;
}
pm_runtime_put(&client->dev);
pm_runtime_mark_last_busy(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
return ret;
}
@@ -1592,22 +1593,23 @@ static int imx708_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0)
goto err_unlock;
}
/*
* Apply default & customized values
* and then start streaming.
*/
ret = imx708_start_streaming(imx708);
if (ret)
goto err_rpm_put;
if (ret) {
pm_runtime_put_sync(&client->dev);
goto err_unlock;
}
} else {
imx708_stop_streaming(imx708);
pm_runtime_put(&client->dev);
pm_runtime_mark_last_busy(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
}
imx708->streaming = enable;
@@ -1621,8 +1623,6 @@ static int imx708_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
err_rpm_put:
pm_runtime_put(&client->dev);
err_unlock:
mutex_unlock(&imx708->mutex);
@@ -2032,10 +2032,16 @@ static int imx708_probe(struct i2c_client *client)
/* Initialize default format */
imx708_set_default_format(imx708);
/* Enable runtime PM and turn off the device */
/*
* Enable runtime PM with autosuspend. As the device has been powered
* manually, mark it as active, and increase the usage count without
* resuming the device.
*/
pm_runtime_set_active(dev);
pm_runtime_get_noresume(dev);
pm_runtime_enable(dev);
pm_runtime_idle(dev);
pm_runtime_set_autosuspend_delay(dev, 5000);
pm_runtime_use_autosuspend(dev);
/* This needs the pm runtime to be registered. */
ret = imx708_init_controls(imx708);
@@ -2064,6 +2070,9 @@ static int imx708_probe(struct i2c_client *client)
goto error_media_entity;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
error_media_entity:
@@ -2073,8 +2082,8 @@ error_handler_free:
imx708_free_controls(imx708);
error_pm_runtime:
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
error_power_off:
imx708_power_off(&client->dev);

View File

@@ -1068,7 +1068,7 @@ static void bcm2835_mmc_set_clock(struct bcm2835_host *host, unsigned int clock)
unsigned long timeout;
unsigned int input_clock = clock;
if (host->overclock_50 && (clock == 50000000))
if (host->overclock_50 && (clock >= 50000000))
clock = host->overclock_50 * 1000000 + 999999;
host->mmc->actual_clock = 0;

View File

@@ -1128,7 +1128,7 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
const unsigned int MHZ = 1000000;
int div;
if (host->overclock_50 && (clock == 50*MHZ))
if (host->overclock_50 && (clock >= 50*MHZ))
clock = host->overclock_50 * MHZ + (MHZ - 1);
/* The SDCDIV register has 11 bits, and holds (div - 2). But

View File

@@ -83,7 +83,7 @@ static inline void pwm_program_init(PIO pio, uint sm, uint offset, uint pin)
/* Write `period` to the input shift register - must be disabled */
static void pio_pwm_set_period(PIO pio, uint sm, uint32_t period)
{
pio_sm_put_blocking(pio, sm, period);
pio_sm_put_blocking(pio, sm, period - 1);
pio_sm_exec(pio, sm, pio_encode_pull(false, false));
pio_sm_exec(pio, sm, pio_encode_out(pio_isr, 32));
}
@@ -101,15 +101,12 @@ static int pwm_pio_rp1_apply(struct pwm_chip *chip, struct pwm_device *pwm,
uint32_t new_duty_cycle;
uint32_t new_period;
if (state->duty_cycle && state->duty_cycle < pwm_pio_resolution)
return -EINVAL;
if (state->duty_cycle != state->period &&
(state->period - state->duty_cycle < pwm_pio_resolution))
return -EINVAL;
new_period = state->period / pwm_pio_resolution;
new_duty_cycle = state->duty_cycle / pwm_pio_resolution;
new_period = DIV_ROUND_CLOSEST(state->period, pwm_pio_resolution);
if (new_period < 2)
new_period = 2;
new_duty_cycle = DIV_ROUND_CLOSEST(state->duty_cycle, pwm_pio_resolution);
if (new_duty_cycle > new_period - 1)
new_duty_cycle = new_period - 1;
mutex_lock(&ppwm->mutex);
@@ -145,8 +142,22 @@ static int pwm_pio_rp1_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
static int pwm_pio_rp1_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
struct pwm_pio_rp1 *ppwm = pwmchip_get_drvdata(chip);
state->enabled = ppwm->enabled;
state->polarity = ppwm->polarity;
state->period = ppwm->period * pwm_pio_resolution;
state->duty_cycle = ppwm->duty_cycle * pwm_pio_resolution;
return 0;
}
static const struct pwm_ops pwm_pio_rp1_ops = {
.apply = pwm_pio_rp1_apply,
.get_state = pwm_pio_rp1_get_state,
};
static int pwm_pio_rp1_probe(struct platform_device *pdev)

View File

@@ -94,7 +94,7 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
}
if (attrs & DMA_ATTR_MMIO) {
dma_addr = phys;
dma_addr = phys_to_dma(dev, phys);
if (unlikely(!dma_capable(dev, dma_addr, size, false)))
goto err_overflow;
} else {