555 lines
16 KiB
Diff
555 lines
16 KiB
Diff
From b6678ec426d7dbc5248a2d98c0c2c7a5b55e4d5f Mon Sep 17 00:00:00 2001
|
|
From: christophe montaud <christophe.montaud@st.com>
|
|
Date: Wed, 16 Jan 2019 17:51:05 +0100
|
|
Subject: [PATCH 56/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DRIVERS
|
|
|
|
---
|
|
drivers/clk/clk-stm32mp1.c | 142 ++++++++++++++++++++--------------
|
|
drivers/i2c/busses/i2c-stm32f7.c | 33 +++++++-
|
|
drivers/irqchip/irq-stm32-exti.c | 160 +++++++++++++++++++++++++--------------
|
|
kernel/power/suspend.c | 1 -
|
|
4 files changed, 218 insertions(+), 118 deletions(-)
|
|
|
|
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
|
|
index 7eccaa1..56d7b86 100644
|
|
--- a/drivers/clk/clk-stm32mp1.c
|
|
+++ b/drivers/clk/clk-stm32mp1.c
|
|
@@ -2215,8 +2215,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = {
|
|
|
|
static const struct clock_config stm32mp1_clock_cfg[] = {
|
|
/* Oscillator divider */
|
|
- DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
|
|
- CLK_DIVIDER_READ_ONLY),
|
|
+ DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO,
|
|
+ RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY),
|
|
|
|
/* External / Internal Oscillators */
|
|
SGATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0),
|
|
@@ -2517,11 +2517,10 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
|
|
CLK_SET_RATE_NO_REPARENT,
|
|
_NO_GATE,
|
|
_MMUX(M_ETHCK),
|
|
- _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)),
|
|
+ _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
|
|
|
|
/* RTC clock */
|
|
- SDIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7,
|
|
- CLK_DIVIDER_ALLOW_ZERO),
|
|
+ SDIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0),
|
|
|
|
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
|
|
CLK_SET_RATE_PARENT,
|
|
@@ -2724,52 +2723,53 @@ static struct sreg clock_gating[] = {
|
|
};
|
|
|
|
struct smux {
|
|
- const char *name;
|
|
- struct clk *clk;
|
|
- struct clk *clkp;
|
|
+ u32 clk_id;
|
|
+ u32 mux_id;
|
|
+ struct clk_hw *hw;
|
|
};
|
|
|
|
-#define KER_SRC(_clk_name)\
|
|
+#define KER_SRC(_clk_id, _mux_id)\
|
|
{\
|
|
- .name = _clk_name,\
|
|
-}
|
|
-
|
|
-struct smux _mux_kernel[] = {
|
|
- KER_SRC("sdmmc1_k"),
|
|
- KER_SRC("spi2_k"),
|
|
- KER_SRC("spi4_k"),
|
|
- KER_SRC("i2c1_k"),
|
|
- KER_SRC("i2c3_k"),
|
|
- KER_SRC("lptim2_k"),
|
|
- KER_SRC("lptim3_k"),
|
|
- KER_SRC("usart2_k"),
|
|
- KER_SRC("usart3_k"),
|
|
- KER_SRC("uart7_k"),
|
|
- KER_SRC("sai1_k"),
|
|
- KER_SRC("ethck_k"),
|
|
- KER_SRC("i2c4_k"),
|
|
- KER_SRC("rng2_k"),
|
|
- KER_SRC("sdmmc3_k"),
|
|
- KER_SRC("fmc_k"),
|
|
- KER_SRC("qspi_k"),
|
|
- KER_SRC("usbphy_k"),
|
|
- KER_SRC("usbo_k"),
|
|
- KER_SRC("spdif_k"),
|
|
- KER_SRC("spi1_k"),
|
|
- KER_SRC("cec_k"),
|
|
- KER_SRC("lptim1_k"),
|
|
- KER_SRC("uart6_k"),
|
|
- KER_SRC("fdcan_k"),
|
|
- KER_SRC("sai2_k"),
|
|
- KER_SRC("sai3_k"),
|
|
- KER_SRC("sai4_k"),
|
|
- KER_SRC("adc12_k"),
|
|
- KER_SRC("dsi_k"),
|
|
- KER_SRC("ck_per"),
|
|
- KER_SRC("rng1_k"),
|
|
- KER_SRC("stgen_k"),
|
|
- KER_SRC("usart1_k"),
|
|
- KER_SRC("spi6_k"),
|
|
+ .clk_id = _clk_id,\
|
|
+ .mux_id = _mux_id,\
|
|
+}
|
|
+
|
|
+struct smux _mux_kernel[M_LAST] = {
|
|
+ KER_SRC(SDMMC1_K, M_SDMMC12),
|
|
+ KER_SRC(SDMMC3_K, M_SDMMC3),
|
|
+ KER_SRC(FMC_K, M_FMC),
|
|
+ KER_SRC(QSPI_K, M_QSPI),
|
|
+ KER_SRC(RNG1_K, M_RNG1),
|
|
+ KER_SRC(RNG2_K, M_RNG2),
|
|
+ KER_SRC(USBPHY_K, M_USBPHY),
|
|
+ KER_SRC(USBO_K, M_USBO),
|
|
+ KER_SRC(STGEN_K, M_STGEN),
|
|
+ KER_SRC(SPDIF_K, M_SPDIF),
|
|
+ KER_SRC(SPI1_K, M_SPI1),
|
|
+ KER_SRC(SPI2_K, M_SPI23),
|
|
+ KER_SRC(SPI4_K, M_SPI45),
|
|
+ KER_SRC(SPI6_K, M_SPI6),
|
|
+ KER_SRC(CEC_K, M_CEC),
|
|
+ KER_SRC(I2C1_K, M_I2C12),
|
|
+ KER_SRC(I2C3_K, M_I2C35),
|
|
+ KER_SRC(I2C4_K, M_I2C46),
|
|
+ KER_SRC(LPTIM1_K, M_LPTIM1),
|
|
+ KER_SRC(LPTIM2_K, M_LPTIM23),
|
|
+ KER_SRC(LPTIM4_K, M_LPTIM45),
|
|
+ KER_SRC(USART1_K, M_USART1),
|
|
+ KER_SRC(USART2_K, M_UART24),
|
|
+ KER_SRC(USART3_K, M_UART35),
|
|
+ KER_SRC(USART6_K, M_USART6),
|
|
+ KER_SRC(UART7_K, M_UART78),
|
|
+ KER_SRC(SAI1_K, M_SAI1),
|
|
+ KER_SRC(SAI2_K, M_SAI2),
|
|
+ KER_SRC(SAI3_K, M_SAI3),
|
|
+ KER_SRC(SAI4_K, M_SAI4),
|
|
+ KER_SRC(DSI_K, M_DSI),
|
|
+ KER_SRC(FDCAN_K, M_FDCAN),
|
|
+ KER_SRC(ADC12_K, M_ADC12),
|
|
+ KER_SRC(ETHCK_K, M_ETHCK),
|
|
+ KER_SRC(CK_PER, M_CKPER),
|
|
};
|
|
|
|
static struct sreg pll_clock[] = {
|
|
@@ -2861,22 +2861,52 @@ static void stm32mp1_restore_pll(struct sreg *sreg, int size)
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_backup_mux(struct smux *smux, int size)
|
|
+static void stm32mp1_backup_mux(struct device_node *np,
|
|
+ struct smux *smux, int size)
|
|
{
|
|
int i;
|
|
+ struct of_phandle_args clkspec;
|
|
+
|
|
+ clkspec.np = np;
|
|
+ clkspec.args_count = 1;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
- smux[i].clk = __clk_lookup(smux[i].name);
|
|
- smux[i].clkp = clk_get_parent(smux[i].clk);
|
|
+ clkspec.args[0] = smux[i].clk_id;
|
|
+ smux[i].hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
|
|
}
|
|
}
|
|
|
|
static void stm32mp1_restore_mux(struct smux *smux, int size)
|
|
{
|
|
int i;
|
|
+ struct clk_hw *hw, *hwp1, *hwp2;
|
|
+ struct mux_cfg *mux;
|
|
+ u8 idx;
|
|
|
|
- for (i = 0; i < size; i++)
|
|
- clk_set_parent_force(smux[i].clk, smux[i].clkp);
|
|
+ /* These MUX are glitch free.
|
|
+ * Then we have to restore mux thru clock framework
|
|
+ * to be sure that CLK_OPS_PARENT_ENABLE will be exploited
|
|
+ */
|
|
+ for (i = 0; i < M_LAST; i++) {
|
|
+ /* get parent strored in clock framework */
|
|
+ hw = smux[i].hw;
|
|
+ hwp1 = clk_hw_get_parent(hw);
|
|
+
|
|
+ /* Get parent corresponding to mux register */
|
|
+ mux = ker_mux_cfg[smux[i].mux_id].mux;
|
|
+ idx = readl_relaxed(rcc_base + mux->reg_off) >> mux->shift;
|
|
+ idx &= (BIT(mux->width) - 1);
|
|
+ hwp2 = clk_hw_get_parent_by_index(hw, idx);
|
|
+
|
|
+ /* check if parent from mux & clock framework are differents */
|
|
+ if (hwp1 != hwp2) {
|
|
+ /* update first clock framework with the true parent */
|
|
+ clk_set_parent(hw->clk, hwp2->clk);
|
|
+
|
|
+ /* Restore now new parent */
|
|
+ clk_set_parent(hw->clk, hwp1->clk);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
#define RCC_BIT_HSI 0
|
|
@@ -2900,9 +2930,6 @@ static int stm32mp1_clk_suspend(void)
|
|
/* Save clock gating regs */
|
|
stm32mp1_backup_sreg(clock_gating, ARRAY_SIZE(clock_gating));
|
|
|
|
- /* Save kernel clock regs */
|
|
- stm32mp1_backup_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel));
|
|
-
|
|
/* Enable ck_xxx_ker clocks if ck_xxx was on */
|
|
reg = readl_relaxed(rcc_base + RCC_OCENSETR) & RCC_CK_OSC_MASK;
|
|
writel_relaxed(reg << 1, rcc_base + RCC_OCENSETR);
|
|
@@ -2970,6 +2997,9 @@ static int stm32_rcc_init_pwr(struct device_node *np)
|
|
|
|
SMC(STM32_SVC_RCC, STM32_WRITE, RCC_SREQCLRR, RCC_STOP_MASK);
|
|
|
|
+ /* Prepare kernel clock source backup */
|
|
+ stm32mp1_backup_mux(np, _mux_kernel, ARRAY_SIZE(_mux_kernel));
|
|
+
|
|
register_syscore_ops(&stm32mp1_clk_ops);
|
|
|
|
return 0;
|
|
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
|
|
index ac30aea..3af2637 100644
|
|
--- a/drivers/i2c/busses/i2c-stm32f7.c
|
|
+++ b/drivers/i2c/busses/i2c-stm32f7.c
|
|
@@ -978,6 +978,26 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
|
|
cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
|
|
f7_msg->read_write = I2C_SMBUS_READ;
|
|
break;
|
|
+ case I2C_SMBUS_I2C_BLOCK_DATA:
|
|
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
|
|
+ dev_err(dev, "Invalid block %s size %d\n",
|
|
+ f7_msg->read_write == I2C_SMBUS_READ ?
|
|
+ "read" : "write",
|
|
+ data->block[0]);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (f7_msg->read_write) {
|
|
+ f7_msg->stop = false;
|
|
+ f7_msg->count = data->block[0];
|
|
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
|
|
+ } else {
|
|
+ f7_msg->stop = true;
|
|
+ f7_msg->count = data->block[0] + 1;
|
|
+ for (i = 1; i <= data->block[0]; i++)
|
|
+ f7_msg->smbus_buf[i] = data->block[i];
|
|
+ }
|
|
+ break;
|
|
default:
|
|
dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
|
|
return -EOPNOTSUPP;
|
|
@@ -986,7 +1006,8 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
|
|
f7_msg->buf = f7_msg->smbus_buf;
|
|
|
|
/* Configure PEC */
|
|
- if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
|
|
+ if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK &&
|
|
+ f7_msg->size != I2C_SMBUS_I2C_BLOCK_DATA) {
|
|
cr1 |= STM32F7_I2C_CR1_PECEN;
|
|
cr2 |= STM32F7_I2C_CR2_PECBYTE;
|
|
if (!f7_msg->read_write)
|
|
@@ -1655,7 +1676,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|
}
|
|
|
|
/* Check PEC */
|
|
- if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
|
|
+ if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK &&
|
|
+ size != I2C_SMBUS_I2C_BLOCK_DATA && read_write) {
|
|
ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
|
|
if (ret)
|
|
goto pm_free;
|
|
@@ -1672,6 +1694,10 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|
data->word = f7_msg->smbus_buf[0] |
|
|
(f7_msg->smbus_buf[1] << 8);
|
|
break;
|
|
+ case I2C_SMBUS_I2C_BLOCK_DATA:
|
|
+ for (i = 0; i < data->block[0]; i++)
|
|
+ data->block[i + 1] = f7_msg->smbus_buf[i];
|
|
+ break;
|
|
case I2C_SMBUS_BLOCK_DATA:
|
|
case I2C_SMBUS_BLOCK_PROC_CALL:
|
|
for (i = 0; i <= f7_msg->smbus_buf[0]; i++)
|
|
@@ -1854,7 +1880,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
|
|
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
|
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
|
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
|
- I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC;
|
|
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
|
|
+ I2C_FUNC_SMBUS_I2C_BLOCK;
|
|
}
|
|
|
|
static struct i2c_algorithm stm32f7_i2c_algo = {
|
|
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
|
|
index 223ee2e..793be075a 100644
|
|
--- a/drivers/irqchip/irq-stm32-exti.c
|
|
+++ b/drivers/irqchip/irq-stm32-exti.c
|
|
@@ -14,8 +14,10 @@
|
|
#include <linux/irqchip.h>
|
|
#include <linux/irqchip/chained_irq.h>
|
|
#include <linux/irqdomain.h>
|
|
+#include <linux/module.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_irq.h>
|
|
+#include <linux/of_platform.h>
|
|
#include <linux/syscore_ops.h>
|
|
|
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
@@ -37,12 +39,6 @@ struct stm32_exti_bank {
|
|
|
|
#define UNDEF_REG ~0
|
|
|
|
-enum stm32_exti_hwspinlock {
|
|
- HWSPINLOCK_UNKNOWN,
|
|
- HWSPINLOCK_NONE,
|
|
- HWSPINLOCK_READY,
|
|
-};
|
|
-
|
|
struct stm32_desc_irq {
|
|
u32 exti;
|
|
u32 irq_parent;
|
|
@@ -69,8 +65,6 @@ struct stm32_exti_host_data {
|
|
void __iomem *base;
|
|
struct stm32_exti_chip_data *chips_data;
|
|
const struct stm32_exti_drv_data *drv_data;
|
|
- struct device_node *node;
|
|
- enum stm32_exti_hwspinlock hwlock_state;
|
|
struct hwspinlock *hwlock;
|
|
};
|
|
|
|
@@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d,
|
|
|
|
static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
|
|
{
|
|
- struct stm32_exti_host_data *host_data = chip_data->host_data;
|
|
- struct hwspinlock *hwlock;
|
|
- int id, ret = 0, timeout = 0;
|
|
-
|
|
- /* first time, check for hwspinlock availability */
|
|
- if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
|
|
- id = of_hwspin_lock_get_id(host_data->node, 0);
|
|
- if (id >= 0) {
|
|
- hwlock = hwspin_lock_request_specific(id);
|
|
- if (hwlock) {
|
|
- /* found valid hwspinlock */
|
|
- host_data->hwlock_state = HWSPINLOCK_READY;
|
|
- host_data->hwlock = hwlock;
|
|
- pr_debug("%s hwspinlock = %d\n", __func__, id);
|
|
- } else {
|
|
- host_data->hwlock_state = HWSPINLOCK_NONE;
|
|
- }
|
|
- } else if (id != -EPROBE_DEFER) {
|
|
- host_data->hwlock_state = HWSPINLOCK_NONE;
|
|
- } else {
|
|
- /* hwspinlock driver shall be ready at that stage */
|
|
- ret = -EPROBE_DEFER;
|
|
- }
|
|
- }
|
|
+ int ret, timeout = 0;
|
|
|
|
- if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) {
|
|
- /*
|
|
- * Use the x_raw API since we are under spin_lock protection.
|
|
- * Do not use the x_timeout API because we are under irq_disable
|
|
- * mode (see __setup_irq())
|
|
- */
|
|
- do {
|
|
- ret = hwspin_trylock_raw(host_data->hwlock);
|
|
- if (!ret)
|
|
- return 0;
|
|
-
|
|
- udelay(HWSPNLCK_RETRY_DELAY);
|
|
- timeout += HWSPNLCK_RETRY_DELAY;
|
|
- } while (timeout < HWSPNLCK_TIMEOUT);
|
|
-
|
|
- if (ret == -EBUSY)
|
|
- ret = -ETIMEDOUT;
|
|
- }
|
|
+ if (!chip_data->host_data->hwlock)
|
|
+ return 0;
|
|
+
|
|
+ /*
|
|
+ * Use the x_raw API since we are under spin_lock protection.
|
|
+ * Do not use the x_timeout API because we are under irq_disable
|
|
+ * mode (see __setup_irq())
|
|
+ */
|
|
+ do {
|
|
+ ret = hwspin_trylock_raw(chip_data->host_data->hwlock);
|
|
+ if (!ret)
|
|
+ return 0;
|
|
+
|
|
+ udelay(HWSPNLCK_RETRY_DELAY);
|
|
+ timeout += HWSPNLCK_RETRY_DELAY;
|
|
+ } while (timeout < HWSPNLCK_TIMEOUT);
|
|
+
|
|
+ if (ret == -EBUSY)
|
|
+ ret = -ETIMEDOUT;
|
|
|
|
if (ret)
|
|
pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
|
|
@@ -337,7 +309,7 @@ static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
|
|
|
|
static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
|
|
{
|
|
- if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY))
|
|
+ if (chip_data->host_data->hwlock)
|
|
hwspin_unlock_raw(chip_data->host_data->hwlock);
|
|
}
|
|
|
|
@@ -710,8 +682,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
|
|
return NULL;
|
|
|
|
host_data->drv_data = dd;
|
|
- host_data->node = node;
|
|
- host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
|
|
host_data->chips_data = kcalloc(dd->bank_nr,
|
|
sizeof(struct stm32_exti_chip_data),
|
|
GFP_KERNEL);
|
|
@@ -738,7 +708,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
|
|
|
|
static struct
|
|
stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
|
|
- u32 bank_idx)
|
|
+ u32 bank_idx,
|
|
+ struct device_node *node)
|
|
{
|
|
const struct stm32_exti_bank *stm32_bank;
|
|
struct stm32_exti_chip_data *chip_data;
|
|
@@ -758,7 +729,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
|
|
writel_relaxed(0, base + stm32_bank->imr_ofst);
|
|
writel_relaxed(0, base + stm32_bank->emr_ofst);
|
|
|
|
- pr_info("%pOF: bank%d\n", h_data->node, bank_idx);
|
|
+ pr_info("%pOF: bank%d\n", node, bank_idx);
|
|
|
|
return chip_data;
|
|
}
|
|
@@ -798,7 +769,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
|
|
struct stm32_exti_chip_data *chip_data;
|
|
|
|
stm32_bank = drv_data->exti_banks[i];
|
|
- chip_data = stm32_exti_chip_init(host_data, i);
|
|
+ chip_data = stm32_exti_chip_init(host_data, i, node);
|
|
|
|
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
|
|
|
|
@@ -880,7 +851,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < drv_data->bank_nr; i++)
|
|
- stm32_exti_chip_init(host_data, i);
|
|
+ stm32_exti_chip_init(host_data, i, node);
|
|
|
|
domain = irq_domain_add_hierarchy(parent_domain, 0,
|
|
drv_data->bank_nr * IRQS_PER_BANK,
|
|
@@ -938,6 +909,71 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
|
|
return ret;
|
|
}
|
|
|
|
+/* Note : stm32_exti_probe() is called after stm32*_exti_of_init() */
|
|
+static int stm32_exti_probe(struct platform_device *pdev)
|
|
+{
|
|
+ int id, ret = 0;
|
|
+
|
|
+ id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
|
|
+
|
|
+ if (id == -EPROBE_DEFER)
|
|
+ /* hwspinlock framework not ready */
|
|
+ return -EPROBE_DEFER;
|
|
+
|
|
+ if (id == -ENOENT)
|
|
+ /* no hwspinlock defined (not an error, it is optional) */
|
|
+ return 0;
|
|
+
|
|
+ if (id >= 0) {
|
|
+ stm32_host_data->hwlock = hwspin_lock_request_specific(id);
|
|
+ if (!stm32_host_data->hwlock) {
|
|
+ dev_err(&pdev->dev, "Failed to request hwspinlock\n");
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+ } else {
|
|
+ dev_err(&pdev->dev, "Failed to get hwspinlock\n");
|
|
+ ret = id;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int stm32_exti_remove(struct platform_device *pdev)
|
|
+{
|
|
+ if (stm32_host_data->hwlock)
|
|
+ return hwspin_lock_free(stm32_host_data->hwlock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id stm32_exti_ids[] = {
|
|
+ { .compatible = "st,stm32mp1-exti", },
|
|
+ {},
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, stm32_exti_ids);
|
|
+
|
|
+static struct platform_driver stm32_exti_driver = {
|
|
+ .probe = stm32_exti_probe,
|
|
+ .remove = stm32_exti_remove,
|
|
+ .driver = {
|
|
+ .name = "stm32_exti",
|
|
+ .of_match_table = stm32_exti_ids,
|
|
+ },
|
|
+};
|
|
+
|
|
+static int __init stm32_exti_arch_init(void)
|
|
+{
|
|
+ return platform_driver_register(&stm32_exti_driver);
|
|
+}
|
|
+
|
|
+static void __exit stm32_exti_arch_exit(void)
|
|
+{
|
|
+ return platform_driver_unregister(&stm32_exti_driver);
|
|
+}
|
|
+
|
|
+arch_initcall(stm32_exti_arch_init);
|
|
+module_exit(stm32_exti_arch_exit);
|
|
+
|
|
static int __init stm32f4_exti_of_init(struct device_node *np,
|
|
struct device_node *parent)
|
|
{
|
|
@@ -957,7 +993,15 @@ IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
|
|
static int __init stm32mp1_exti_of_init(struct device_node *np,
|
|
struct device_node *parent)
|
|
{
|
|
- return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
|
|
+ int ret;
|
|
+
|
|
+ ret = stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
|
|
+
|
|
+ /* Clear the OF_POPULATED flag so that stm32_exti_probe can be called */
|
|
+ if (!ret)
|
|
+ of_node_clear_flag(np, OF_POPULATED);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);
|
|
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
|
|
index 0bd595a..64f6aec 100644
|
|
--- a/kernel/power/suspend.c
|
|
+++ b/kernel/power/suspend.c
|
|
@@ -36,7 +36,6 @@
|
|
#include "power.h"
|
|
|
|
const char * const pm_labels[] = {
|
|
- [PM_SUSPEND_TO_IDLE] = "freeze",
|
|
[PM_SUSPEND_STANDBY] = "standby",
|
|
[PM_SUSPEND_MEM] = "mem",
|
|
};
|
|
--
|
|
2.7.4
|
|
|