Merge: S32G: update drivers to v7.2

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/3359

## Summary of Changes

Update S32G-related drivers to sync with v7.2. This excludes a couple of areas:

* `hwmon` changes will be broken out into their own MR since there are nontrivial changes that are currently in `linux-next`.
* `stmmac` requires `ethernet` acks, so related changes are broken out to !3360 to make review easier and avoid blocking the rest of the S32G updates on those patches. Changes not specific to S32G are omitted since they'll presumably be picked up in the next subsystem update.

## Approved Development Ticket(s)

JIRA: https://redhat.atlassian.net/browse/RHEL-248519

Signed-off-by: Jared Kangas <jkangas@redhat.com>

Approved-by: Tony Camuso <tcamuso@redhat.com>
Approved-by: Eric Chanudet <echanude@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
CKI KWF Bot
2026-09-04 06:45:35 +00:00
11 changed files with 360 additions and 199 deletions
@@ -109,13 +109,13 @@ examples:
big-endian;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <16000000>;
spi-cpol;
spi-cpha;
spi-cs-setup-delay-ns = <100>;
spi-cs-hold-delay-ns = <50>;
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <16000000>;
spi-cpol;
spi-cpha;
spi-cs-setup-delay-ns = <100>;
spi-cs-hold-delay-ns = <50>;
};
};
# S32G3 in target mode
@@ -0,0 +1,59 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/fsl,vf610-pit.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Periodic Interrupt Timer (PIT)
maintainers:
- Frank Li <Frank.Li@nxp.com>
description:
The PIT module is an array of timers that can be used to raise interrupts
and trigger DMA channels.
properties:
compatible:
oneOf:
- enum:
- fsl,vf610-pit
- nxp,s32g2-pit
- items:
- const: nxp,s32g3-pit
- const: nxp,s32g2-pit
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: pit
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/vf610-clock.h>
#include <dt-bindings/interrupt-controller/irq.h>
timer@40037000 {
compatible = "fsl,vf610-pit";
reg = <0x40037000 0x1000>;
interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks VF610_CLK_PIT>;
clock-names = "pit";
};
+27 -7
View File
@@ -605,20 +605,28 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *
return 0;
}
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc,
unsigned int off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = pca953x_get_bit_mask(chip, off);
guard(mutex)(&chip->i2c_lock);
if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE)
return regmap_update_bits(chip->regmap, dirreg, bit, 0);
return regmap_update_bits(chip->regmap, dirreg, bit, bit);
}
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
guard(mutex)(&chip->i2c_lock);
return pca953x_gpio_direction_input_unlocked(gc, off);
}
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
@@ -856,9 +864,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
DECLARE_BITMAP(reg_direction, MAX_LINE);
int level;
guard(mutex)(&chip->i2c_lock);
if (chip->driver_data & PCA_PCAL) {
DECLARE_BITMAP(latched_inputs, MAX_LINE);
guard(mutex)(&chip->i2c_lock);
/* Enable latch on edge-triggered interrupt-enabled inputs */
bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
@@ -880,7 +889,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
/* Look for any newly setup interrupt */
for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
pca953x_gpio_direction_input(&chip->gpio_chip, level);
pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level);
mutex_unlock(&chip->irq_lock);
}
@@ -1370,9 +1379,20 @@ static int pca953x_restore_context(struct pca953x_chip *chip)
regcache_mark_dirty(chip->regmap);
ret = pca953x_regcache_sync(chip);
if (ret)
return ret;
goto err;
return regcache_sync(chip->regmap);
ret = regcache_sync(chip->regmap);
if (ret)
goto err;
return 0;
err:
if (chip->client->irq > 0)
disable_irq(chip->client->irq);
regcache_cache_only(chip->regmap, true);
return ret;
}
static void pca953x_save_context(struct pca953x_chip *chip)
+82 -8
View File
@@ -930,9 +930,6 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
if (i2c_imx->slave)
return -EBUSY;
i2c_imx->slave = client;
i2c_imx->last_slave_event = I2C_SLAVE_STOP;
/* Resume */
ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
if (ret < 0) {
@@ -940,6 +937,11 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
return ret;
}
scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) {
i2c_imx->slave = client;
i2c_imx->last_slave_event = I2C_SLAVE_STOP;
}
i2c_imx_slave_init(i2c_imx);
return 0;
@@ -958,6 +960,7 @@ static int i2c_imx_unreg_slave(struct i2c_client *client)
i2c_imx_reset_regs(i2c_imx);
hrtimer_cancel(&i2c_imx->slave_timer);
i2c_imx->slave = NULL;
/* Suspend */
@@ -1061,11 +1064,28 @@ static inline enum imx_i2c_state i2c_imx_isr_read_continue(struct imx_i2c_struct
static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx)
{
u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
unsigned int temp;
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
/*
* SMBus 3.1 6.5.7: support count byte of 0.
* I2C_SMBUS_BLOCK_MAX case should not hold the SDA either.
* So NACK it (TXAK) to not hold the bus.
*/
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
if (len == 0) {
i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = 0;
i2c_imx->msg->len = 2;
return;
}
i2c_imx->isr_result = -EPROTO;
i2c_imx->state = IMX_I2C_STATE_FAILED;
wake_up(&i2c_imx->queue);
return;
}
i2c_imx->msg->len += len;
i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = len;
@@ -1415,6 +1435,7 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
int i, result;
unsigned int temp;
int block_data = msgs->flags & I2C_M_RECV_LEN;
int block_err = 0;
result = i2c_imx_prepare_read(i2c_imx, msgs, false);
if (result)
@@ -1436,8 +1457,20 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
*/
if ((!i) && block_data) {
len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
return -EPROTO;
if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
/*
* SMBus 3.1 6.5.7: support count byte of 0.
* I2C_SMBUS_BLOCK_MAX case should not hold the SDA either.
*/
if (len > I2C_SMBUS_BLOCK_MAX)
block_err = -EPROTO;
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
msgs->buf[0] = 0;
msgs->len = 2;
continue;
}
dev_dbg(&i2c_imx->adapter.dev,
"<%s> read length: 0x%X\n",
__func__, len);
@@ -1485,7 +1518,7 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
}
return 0;
return block_err;
}
static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
@@ -1924,6 +1957,47 @@ static int i2c_imx_runtime_resume(struct device *dev)
return 0;
}
static int __maybe_unused i2c_imx_suspend_noirq(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
i2c_mark_adapter_suspended(&i2c_imx->adapter);
/*
* Cancel the slave timer before powering down to prevent
* i2c_imx_slave_timeout() from accessing hardware registers
* while the clock is disabled.
*/
hrtimer_cancel(&i2c_imx->slave_timer);
ret = pm_runtime_force_suspend(dev);
if (ret) {
i2c_mark_adapter_resumed(&i2c_imx->adapter);
if (i2c_imx->slave) {
hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY);
hrtimer_restart(&i2c_imx->slave_timer);
}
return ret;
}
return 0;
}
static int __maybe_unused i2c_imx_resume_noirq(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
i2c_mark_adapter_resumed(&i2c_imx->adapter);
return 0;
}
static int i2c_imx_suspend(struct device *dev)
{
/*
@@ -1958,8 +2032,8 @@ static int i2c_imx_resume(struct device *dev)
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend_noirq,
i2c_imx_resume_noirq)
SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
};
+58 -33
View File
@@ -1315,19 +1315,21 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
if (IS_ERR(imx_data->pinctrl) ||
IS_ERR(imx_data->pins_100mhz) ||
IS_ERR(imx_data->pins_200mhz))
if (IS_ERR(imx_data->pinctrl))
return -EINVAL;
switch (uhs) {
case MMC_TIMING_UHS_SDR50:
case MMC_TIMING_UHS_DDR50:
if (IS_ERR(imx_data->pins_100mhz))
return -EINVAL;
pinctrl = imx_data->pins_100mhz;
break;
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200:
case MMC_TIMING_MMC_HS400:
if (IS_ERR(imx_data->pins_200mhz))
return -EINVAL;
pinctrl = imx_data->pins_200mhz;
break;
default:
@@ -1338,6 +1340,23 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
return pinctrl_select_state(imx_data->pinctrl, pinctrl);
}
static void esdhc_set_dll_override(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
u32 v;
if (!boarddata->delay_line)
return;
v = boarddata->delay_line << ESDHC_DLL_OVERRIDE_VAL_SHIFT |
(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
if (is_imx53_esdhc(imx_data))
v <<= 1;
writel(v, host->ioaddr + ESDHC_DLL_CTRL);
}
/*
* For HS400 eMMC, there is a data_strobe line. This signal is generated
* by the device and used for data output and CRC status response output
@@ -1393,7 +1412,6 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
u32 m;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
/* disable ddr mode and disable HS400 mode */
m = readl(host->ioaddr + ESDHC_MIX_CTRL);
@@ -1414,15 +1432,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
m |= ESDHC_MIX_CTRL_DDREN;
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
imx_data->is_ddr = 1;
if (boarddata->delay_line) {
u32 v;
v = boarddata->delay_line <<
ESDHC_DLL_OVERRIDE_VAL_SHIFT |
(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
if (is_imx53_esdhc(imx_data))
v <<= 1;
writel(v, host->ioaddr + ESDHC_DLL_CTRL);
}
esdhc_set_dll_override(host);
break;
case MMC_TIMING_MMC_HS400:
m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
@@ -2028,7 +2038,9 @@ static int sdhci_esdhc_suspend(struct device *dev)
* 2, make sure the pm_runtime_force_resume() in sdhci_esdhc_resume() really
* invoke its ->runtime_resume callback (needs_force_resume = 1).
*/
pm_runtime_get_sync(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
@@ -2041,15 +2053,14 @@ static int sdhci_esdhc_suspend(struct device *dev)
* to save the tuning delay value just in case the usdhc
* lost power during system PM.
*/
if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
esdhc_is_usdhc(imx_data))
if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
sdhc_esdhc_tuning_save(host);
/* The irqs of imx are not shared. It is safe to disable */
disable_irq(host->irq);
if (device_may_wakeup(dev)) {
/* The irqs of imx are not shared. It is safe to disable */
disable_irq(host->irq);
ret = sdhci_enable_irq_wakeups(host);
if (!ret)
if (!sdhci_enable_irq_wakeups(host))
dev_warn(dev, "Failed to enable irq wakeup\n");
} else {
/*
@@ -2060,12 +2071,12 @@ static int sdhci_esdhc_suspend(struct device *dev)
* other function like GPIO function to save power in PM,
* which finally block the SDIO wakeup function.
*/
ret = pinctrl_pm_select_sleep_state(dev);
if (ret)
return ret;
if (pinctrl_pm_select_sleep_state(dev))
dev_warn(dev, "Failed to select sleep pinctrl state\n");
}
ret = mmc_gpio_set_cd_wake(host->mmc, true);
if (mmc_gpio_set_cd_wake(host->mmc, true))
dev_warn(dev, "Failed to enable cd wake\n");
/*
* Make sure invoke runtime_suspend to gate off clock.
@@ -2073,7 +2084,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
*/
pm_runtime_force_suspend(dev);
return ret;
return 0;
}
static int sdhci_esdhc_resume(struct device *dev)
@@ -2083,31 +2094,45 @@ static int sdhci_esdhc_resume(struct device *dev)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int ret;
pm_runtime_force_resume(dev);
if (!device_may_wakeup(dev)) {
ret = esdhc_change_pinstate(host, host->timing);
if (ret)
dev_warn(dev, "Failed to restore pinctrl state\n");
}
ret = mmc_gpio_set_cd_wake(host->mmc, false);
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
mmc_gpio_set_cd_wake(host->mmc, false);
/* re-initialize hw state in case it's lost in low power mode */
sdhci_esdhc_imx_hwinit(host);
if (host->irq_wake_enabled) {
if (host->irq_wake_enabled)
sdhci_disable_irq_wakeups(host);
enable_irq(host->irq);
}
enable_irq(host->irq);
/*
* restore the saved tuning delay value for the device which keep
* power during system PM.
*/
if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
esdhc_is_usdhc(imx_data))
if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data)) {
sdhc_esdhc_tuning_restore(host);
/*
* Restore DLL override for DDR modes. hwinit unconditionally
* clears ESDHC_DLL_CTRL, but the card is still in DDR mode.
*/
if (host->timing == MMC_TIMING_UHS_DDR50 ||
host->timing == MMC_TIMING_MMC_DDR52)
esdhc_set_dll_override(host);
}
pm_runtime_put_autosuspend(dev);
return ret;
return 0;
}
static int sdhci_esdhc_runtime_suspend(struct device *dev)
+1 -1
View File
@@ -16,7 +16,7 @@ struct platform_device;
/**
* struct s32_pin_group - describes an S32 pin group
* @data: generic data describes group name, number of pins, and a pin array in
this group.
* this group.
* @pin_sss: an array of source signal select configs paired with pin array.
*/
struct s32_pin_group {
+30 -34
View File
@@ -2,7 +2,7 @@
/*
* Core driver for the S32 CC (Common Chassis) pin controller
*
* Copyright 2017-2022,2024 NXP
* Copyright 2017-2022,2024-2025 NXP
* Copyright (C) 2022 SUSE LLC
* Copyright 2015-2016 Freescale Semiconductor, Inc.
*/
@@ -236,10 +236,10 @@ static int s32_dt_group_node_to_map(struct pinctrl_dev *pctldev,
}
ret = pinconf_generic_parse_dt_config(np, pctldev, &cfgs, &n_cfgs);
if (ret) {
dev_err(dev, "%pOF: could not parse node property\n", np);
return ret;
}
if (ret)
return dev_err_probe(dev, ret,
"%pOF: could not parse node property\n",
np);
if (n_cfgs)
reserve++;
@@ -763,15 +763,15 @@ static int s32_pinctrl_parse_groups(struct device_node *np,
grp->data.name = np->name;
npins = of_property_count_elems_of_size(np, "pinmux", sizeof(u32));
if (npins < 0) {
dev_err(dev, "Failed to read 'pinmux' property in node %s.\n",
grp->data.name);
return -EINVAL;
}
if (!npins) {
dev_err(dev, "The group %s has no pins.\n", grp->data.name);
return -EINVAL;
}
if (npins < 0)
return dev_err_probe(dev, -EINVAL,
"Failed to read 'pinmux' in node %s\n",
grp->data.name);
if (!npins)
return dev_err_probe(dev, -EINVAL,
"The group %s has no pins\n",
grp->data.name);
grp->data.npins = npins;
@@ -812,10 +812,9 @@ static int s32_pinctrl_parse_functions(struct device_node *np,
/* Initialise function */
func->name = np->name;
func->ngroups = of_get_child_count(np);
if (func->ngroups == 0) {
dev_err(info->dev, "no groups defined in %pOF\n", np);
return -EINVAL;
}
if (func->ngroups == 0)
return dev_err_probe(info->dev, -EINVAL,
"No groups defined in %pOF\n", np);
groups = devm_kcalloc(info->dev, func->ngroups,
sizeof(*func->groups), GFP_KERNEL);
@@ -886,10 +885,9 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
}
nfuncs = of_get_child_count(np);
if (nfuncs <= 0) {
dev_err(&pdev->dev, "no functions defined\n");
return -EINVAL;
}
if (nfuncs <= 0)
return dev_err_probe(&pdev->dev, -EINVAL,
"No functions defined\n");
info->nfunctions = nfuncs;
info->functions = devm_kcalloc(&pdev->dev, nfuncs,
@@ -919,18 +917,17 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
int s32_pinctrl_probe(struct platform_device *pdev,
const struct s32_pinctrl_soc_data *soc_data)
{
struct s32_pinctrl *ipctl;
int ret;
struct pinctrl_desc *s32_pinctrl_desc;
struct s32_pinctrl_soc_info *info;
#ifdef CONFIG_PM_SLEEP
struct s32_pinctrl_context *saved_context;
#endif
struct pinctrl_desc *s32_pinctrl_desc;
struct s32_pinctrl_soc_info *info;
struct s32_pinctrl *ipctl;
int ret;
if (!soc_data || !soc_data->pins || !soc_data->npins) {
dev_err(&pdev->dev, "wrong pinctrl info\n");
return -EINVAL;
}
if (!soc_data || !soc_data->pins || !soc_data->npins)
return dev_err_probe(&pdev->dev, -EINVAL,
"Wrong pinctrl info\n");
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -965,10 +962,9 @@ int s32_pinctrl_probe(struct platform_device *pdev,
s32_pinctrl_desc->owner = THIS_MODULE;
ret = s32_pinctrl_probe_dt(pdev, ipctl);
if (ret) {
dev_err(&pdev->dev, "fail to probe dt properties\n");
return ret;
}
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Fail to probe dt properties\n");
ipctl->pctl = devm_pinctrl_register(&pdev->dev, s32_pinctrl_desc,
ipctl);
+41 -61
View File
@@ -544,30 +544,31 @@ static irqreturn_t ci_irq_handler(int irq, void *data)
if (ret == IRQ_HANDLED)
return ret;
}
}
/*
* Handle id change interrupt, it indicates device/host function
* switch.
*/
if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
ci->id_event = true;
/* Clear ID change irq status */
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
ci_otg_queue_work(ci);
return IRQ_HANDLED;
}
/*
* Handle id change interrupt, it indicates device/host function
* switch.
*/
if ((otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
ci->id_event = true;
/* Clear ID change irq status */
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
}
/*
* Handle vbus change interrupt, it indicates device connection
* and disconnection events.
*/
if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
ci->b_sess_valid_event = true;
/* Clear BSV irq */
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
ci_otg_queue_work(ci);
return IRQ_HANDLED;
/*
* Handle vbus change interrupt, it indicates device connection
* and disconnection events.
*/
if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
ci->b_sess_valid_event = true;
/* Clear BSV irq */
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
}
if (ci->id_event || ci->b_sess_valid_event) {
ci_otg_queue_work(ci);
return IRQ_HANDLED;
}
}
/* Handle device/host interrupt */
@@ -618,28 +619,13 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
struct ci_hdrc_cable *cable;
if (role == USB_ROLE_HOST) {
cable = &ci->platdata->id_extcon;
cable->changed = true;
cable->connected = true;
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = false;
} else if (role == USB_ROLE_DEVICE) {
cable = &ci->platdata->id_extcon;
cable->changed = true;
cable->connected = false;
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = true;
} else {
cable = &ci->platdata->id_extcon;
cable->changed = true;
cable->connected = false;
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = false;
}
cable = &ci->platdata->id_extcon;
cable->changed = true;
cable->connected = (role == USB_ROLE_HOST);
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = (role == USB_ROLE_DEVICE);
ci_irq(ci);
return 0;
@@ -669,12 +655,6 @@ static enum ci_role ci_get_role(struct ci_hdrc *ci)
return role;
}
static struct usb_role_switch_desc ci_role_switch = {
.set = ci_usb_role_switch_set,
.get = ci_usb_role_switch_get,
.allow_userspace_control = true,
};
static int ci_get_platdata(struct device *dev,
struct ci_hdrc_platform_data *platdata)
{
@@ -801,9 +781,6 @@ static int ci_get_platdata(struct device *dev,
cable->connected = false;
}
if (device_property_read_bool(dev, "usb-role-switch"))
ci_role_switch.fwnode = dev->fwnode;
platdata->pctl = devm_pinctrl_get(dev);
if (!IS_ERR(platdata->pctl)) {
struct pinctrl_state *p;
@@ -1047,6 +1024,7 @@ ATTRIBUTE_GROUPS(ci);
static int ci_hdrc_probe(struct platform_device *pdev)
{
struct usb_role_switch_desc ci_role_switch = {};
struct device *dev = &pdev->dev;
struct ci_hdrc *ci;
struct resource *res;
@@ -1193,7 +1171,11 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
}
if (ci_role_switch.fwnode) {
if (device_property_read_bool(dev, "usb-role-switch")) {
ci_role_switch.set = ci_usb_role_switch_set;
ci_role_switch.get = ci_usb_role_switch_get;
ci_role_switch.allow_userspace_control = true;
ci_role_switch.fwnode = dev_fwnode(dev);
ci_role_switch.driver_data = ci;
ci->role_switch = usb_role_switch_register(dev,
&ci_role_switch);
@@ -1205,19 +1187,16 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ci->role = ci_get_role(ci);
if (!ci_otg_is_fsm_mode(ci)) {
/* only update vbus status for peripheral */
if (ci->role == CI_ROLE_GADGET) {
/* Pull down DP for possible charger detection */
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
ci_handle_vbus_change(ci);
}
ret = ci_role_start(ci, ci->role);
if (ret) {
dev_err(dev, "can't start %s role\n",
ci_role(ci)->name);
goto stop;
}
/* only update vbus status for peripheral */
if (ci->role == CI_ROLE_GADGET)
ci_handle_vbus_change(ci);
}
ret = devm_request_irq(dev, ci->irq, ci_irq_handler, IRQF_SHARED,
@@ -1271,6 +1250,7 @@ static void ci_hdrc_remove(struct platform_device *pdev)
usb_role_switch_unregister(ci->role_switch);
if (ci->supports_runtime_pm) {
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
+5 -2
View File
@@ -130,6 +130,9 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)
void ci_handle_vbus_change(struct ci_hdrc *ci)
{
if (ci->role != CI_ROLE_GADGET)
return;
if (!ci->is_otg) {
if (ci->platdata->flags & CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS)
usb_gadget_vbus_connect(&ci->gadget);
@@ -187,8 +190,8 @@ void ci_handle_id_switch(struct ci_hdrc *ci)
ci_role_stop(ci);
if (role == CI_ROLE_GADGET &&
IS_ERR(ci->platdata->vbus_extcon.edev))
if (role == CI_ROLE_GADGET && !ci->role_switch &&
IS_ERR(ci->platdata->vbus_extcon.edev))
/*
* Wait vbus lower than OTGSC_BSV before connecting
* to host. If connecting status is from an external
+49 -44
View File
@@ -1835,6 +1835,20 @@ static const struct usb_ep_ops usb_ep_ops = {
* GADGET block
*****************************************************************************/
static void ci_udc_enable_vbus_irq(struct ci_hdrc *ci, bool enable)
{
u32 reg = OTGSC_BSVIS;
if (!ci->is_otg)
return;
if (enable)
reg |= OTGSC_BSVIE;
/* Clear pending BSVIS and enable/disable BSVIE */
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, reg);
}
static int ci_udc_get_frame(struct usb_gadget *_gadget)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
@@ -2030,6 +2044,8 @@ static int init_eps(struct ci_hdrc *ci)
{
int retval = 0, i, j;
memset(ci->ci_hw_ep, 0, sizeof(ci->ci_hw_ep));
for (i = 0; i < ci->hw_ep_max/2; i++)
for (j = RX; j <= TX; j++) {
int k = i + j * ci->hw_ep_max/2;
@@ -2275,6 +2291,8 @@ static int udc_start(struct ci_hdrc *ci)
struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
int retval = 0;
memset(&ci->gadget, 0, sizeof(ci->gadget));
ci->gadget.ops = &usb_gadget_ops;
ci->gadget.speed = USB_SPEED_UNKNOWN;
ci->gadget.max_speed = USB_SPEED_HIGH;
@@ -2313,10 +2331,15 @@ static int udc_start(struct ci_hdrc *ci)
ci->gadget.ep0 = &ci->ep0in->ep;
if (ci->platdata->pins_device)
pinctrl_select_state(ci->platdata->pctl,
ci->platdata->pins_device);
retval = usb_add_gadget_udc(dev, &ci->gadget);
if (retval)
goto destroy_eps;
ci_udc_enable_vbus_irq(ci, true);
return retval;
destroy_eps:
@@ -2328,48 +2351,20 @@ free_qh_pool:
return retval;
}
/*
* ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
*
* No interrupts active, the IRQ has been released
/**
* udc_stop: deinitialize gadget role
* @ci: chipidea controller
*/
void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
static void udc_stop(struct ci_hdrc *ci)
{
if (!ci->roles[CI_ROLE_GADGET])
return;
ci_udc_enable_vbus_irq(ci, false);
usb_del_gadget_udc(&ci->gadget);
ci->vbus_active = 0;
destroy_eps(ci);
dma_pool_destroy(ci->td_pool);
dma_pool_destroy(ci->qh_pool);
}
static int udc_id_switch_for_device(struct ci_hdrc *ci)
{
if (ci->platdata->pins_device)
pinctrl_select_state(ci->platdata->pctl,
ci->platdata->pins_device);
if (ci->is_otg)
/* Clear and enable BSV irq */
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
OTGSC_BSVIS | OTGSC_BSVIE);
return 0;
}
static void udc_id_switch_for_host(struct ci_hdrc *ci)
{
/*
* host doesn't care B_SESSION_VALID event
* so clear and disable BSV irq
*/
if (ci->is_otg)
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
ci->vbus_active = 0;
if (ci->platdata->pins_device && ci->platdata->pins_default)
pinctrl_select_state(ci->platdata->pctl,
@@ -2395,9 +2390,7 @@ static void udc_suspend(struct ci_hdrc *ci)
static void udc_resume(struct ci_hdrc *ci, bool power_lost)
{
if (power_lost) {
if (ci->is_otg)
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
OTGSC_BSVIS | OTGSC_BSVIE);
ci_udc_enable_vbus_irq(ci, true);
if (ci->vbus_active)
usb_gadget_vbus_disconnect(&ci->gadget);
} else if (ci->vbus_active && ci->driver &&
@@ -2420,7 +2413,6 @@ static void udc_resume(struct ci_hdrc *ci, bool power_lost)
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
int ret;
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
return -ENXIO;
@@ -2429,8 +2421,8 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
if (!rdrv)
return -ENOMEM;
rdrv->start = udc_id_switch_for_device;
rdrv->stop = udc_id_switch_for_host;
rdrv->start = udc_start;
rdrv->stop = udc_stop;
#ifdef CONFIG_PM_SLEEP
rdrv->suspend = udc_suspend;
rdrv->resume = udc_resume;
@@ -2438,9 +2430,22 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
rdrv->irq = udc_irq;
rdrv->name = "gadget";
ret = udc_start(ci);
if (!ret)
ci->roles[CI_ROLE_GADGET] = rdrv;
ci->roles[CI_ROLE_GADGET] = rdrv;
return ret;
/* Pull down DP for possible charger detection */
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
return 0;
}
/*
* ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
*
* No interrupts active, the IRQ has been released
*/
void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
{
struct device *dev = &ci->gadget.dev;
if (ci->roles[CI_ROLE_GADGET] && device_is_registered(dev))
udc_stop(ci);
}
+1 -2
View File
@@ -56,8 +56,7 @@ MODULE_PARM_DESC(early_enable,
static const struct watchdog_info s32g_wdt_info = {
.identity = "s32g watchdog",
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
WDIOC_GETTIMEOUT | WDIOC_GETTIMELEFT,
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
};
static struct s32g_wdt_device *wdd_to_s32g_wdt(struct watchdog_device *wdd)