i2c-host for v6.17, part 2

- apple: add support for Apple A7–A11, T2 chips
 - qcom-geni: fix controller frequency mapping
 - stm32f7: add DMA-safe transfer support
 - tegra: use controller reset if device reset is missing
 - tegra: remove unnecessary dma_sync*() calls
 -----BEGIN PGP SIGNATURE-----
 
 iIwEABYKADQWIQScDfrjQa34uOld1VLaeAVmJtMtbgUCaI3XghYcYW5kaS5zaHl0
 aUBrZXJuZWwub3JnAAoJENp4BWYm0y1u9moA/1bAEgLdl934yksPMliGIobJUj86
 YuQHK0kloCsppJBVAP9o2pS7avHBeiPLJ89pwsMSu1s/yPm7NzO52Q/FYB3rCA==
 =jmKU
 -----END PGP SIGNATURE-----

Merge tag 'i2c-host-6.17-pt2' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-mergewindow

i2c-host for v6.17, part 2

- apple: add support for Apple A7–A11, T2 chips
- qcom-geni: fix controller frequency mapping
- stm32f7: add DMA-safe transfer support
- tegra: use controller reset if device reset is missing
- tegra: remove unnecessary dma_sync*() calls
pull/1314/head
Wolfram Sang 2025-08-03 22:25:12 +02:00
commit efb2ad898d
4 changed files with 73 additions and 34 deletions

View File

@ -22,6 +22,11 @@ properties:
compatible: compatible:
items: items:
- enum: - enum:
- apple,s5l8960x-i2c
- apple,t7000-i2c
- apple,s8000-i2c
- apple,t8010-i2c
- apple,t8015-i2c
- apple,t8103-i2c - apple,t8103-i2c
- apple,t8112-i2c - apple,t8112-i2c
- apple,t6000-i2c - apple,t6000-i2c

View File

@ -155,9 +155,9 @@ static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
/* source_clock = 32 MHz */ /* source_clock = 32 MHz */
static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = {
{ I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 40 }, { I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 38 },
{ I2C_MAX_FAST_MODE_FREQ, 4, 3, 11, 20 }, { I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 },
{ I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 6, 15 }, { I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 5, 15 },
{} {}
}; };

View File

@ -742,11 +742,14 @@ static void stm32f7_i2c_dma_callback(void *arg)
{ {
struct stm32f7_i2c_dev *i2c_dev = arg; struct stm32f7_i2c_dev *i2c_dev = arg;
struct stm32_i2c_dma *dma = i2c_dev->dma; struct stm32_i2c_dma *dma = i2c_dev->dma;
struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
stm32f7_i2c_disable_dma_req(i2c_dev); stm32f7_i2c_disable_dma_req(i2c_dev);
dmaengine_terminate_async(dma->chan_using); dmaengine_terminate_async(dma->chan_using);
dma_unmap_single(i2c_dev->dev, dma->dma_buf, dma->dma_len, dma_unmap_single(i2c_dev->dev, dma->dma_buf, dma->dma_len,
dma->dma_data_dir); dma->dma_data_dir);
if (!f7_msg->smbus)
i2c_put_dma_safe_msg_buf(f7_msg->buf, i2c_dev->msg, true);
complete(&dma->dma_complete); complete(&dma->dma_complete);
} }
@ -882,6 +885,7 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
{ {
struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
void __iomem *base = i2c_dev->base; void __iomem *base = i2c_dev->base;
u8 *dma_buf;
u32 cr1, cr2; u32 cr1, cr2;
int ret; int ret;
@ -931,17 +935,23 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
/* Configure DMA or enable RX/TX interrupt */ /* Configure DMA or enable RX/TX interrupt */
i2c_dev->use_dma = false; i2c_dev->use_dma = false;
if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN if (i2c_dev->dma && !i2c_dev->atomic) {
&& !i2c_dev->atomic) { dma_buf = i2c_get_dma_safe_msg_buf(msg, STM32F7_I2C_DMA_LEN_MIN);
ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, if (dma_buf) {
msg->flags & I2C_M_RD, f7_msg->buf = dma_buf;
f7_msg->count, f7_msg->buf, ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
stm32f7_i2c_dma_callback, msg->flags & I2C_M_RD,
i2c_dev); f7_msg->count, f7_msg->buf,
if (!ret) stm32f7_i2c_dma_callback,
i2c_dev->use_dma = true; i2c_dev);
else if (ret) {
dev_warn(i2c_dev->dev, "can't use DMA\n"); dev_warn(i2c_dev->dev, "can't use DMA\n");
i2c_put_dma_safe_msg_buf(f7_msg->buf, msg, false);
f7_msg->buf = msg->buf;
} else {
i2c_dev->use_dma = true;
}
}
} }
if (!i2c_dev->use_dma) { if (!i2c_dev->use_dma) {

View File

@ -134,6 +134,8 @@
#define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16) #define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16)
#define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0) #define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0)
#define I2C_MASTER_RESET_CNTRL 0x0a8
/* configuration load timeout in microseconds */ /* configuration load timeout in microseconds */
#define I2C_CONFIG_LOAD_TIMEOUT 1000000 #define I2C_CONFIG_LOAD_TIMEOUT 1000000
@ -184,6 +186,9 @@ enum msg_end_type {
* @has_mst_fifo: The I2C controller contains the new MST FIFO interface that * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that
* provides additional features and allows for longer messages to * provides additional features and allows for longer messages to
* be transferred in one go. * be transferred in one go.
* @has_mst_reset: The I2C controller contains MASTER_RESET_CTRL register which
* provides an alternative to controller reset when configured as
* I2C master
* @quirks: I2C adapter quirks for limiting write/read transfer size and not * @quirks: I2C adapter quirks for limiting write/read transfer size and not
* allowing 0 length transfers. * allowing 0 length transfers.
* @supports_bus_clear: Bus Clear support to recover from bus hang during * @supports_bus_clear: Bus Clear support to recover from bus hang during
@ -213,6 +218,7 @@ struct tegra_i2c_hw_feature {
bool has_multi_master_mode; bool has_multi_master_mode;
bool has_slcg_override_reg; bool has_slcg_override_reg;
bool has_mst_fifo; bool has_mst_fifo;
bool has_mst_reset;
const struct i2c_adapter_quirks *quirks; const struct i2c_adapter_quirks *quirks;
bool supports_bus_clear; bool supports_bus_clear;
bool has_apb_dma; bool has_apb_dma;
@ -605,12 +611,42 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
return 0; return 0;
} }
static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
{
if (!i2c_dev->hw->has_mst_reset)
return -EOPNOTSUPP;
/*
* Writing 1 to I2C_MASTER_RESET_CNTRL will reset all internal state of
* Master logic including FIFOs. Clear this bit to 0 for normal operation.
* SW needs to wait for 2us after assertion and de-assertion of this soft
* reset.
*/
i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL);
fsleep(2);
i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL);
fsleep(2);
return 0;
}
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
{ {
u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode; u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode;
struct i2c_timings *t = &i2c_dev->timings; struct i2c_timings *t = &i2c_dev->timings;
int err; int err;
/*
* Reset the controller before initializing it.
* In case if device_reset() returns -ENOENT, i.e. when the reset is
* not available, the internal software reset will be used if it is
* supported by the controller.
*/
err = device_reset(i2c_dev->dev);
if (err == -ENOENT)
err = tegra_i2c_master_reset(i2c_dev);
/* /*
* The reset shouldn't ever fail in practice. The failure will be a * The reset shouldn't ever fail in practice. The failure will be a
* sign of a severe problem that needs to be resolved. Still we don't * sign of a severe problem that needs to be resolved. Still we don't
@ -619,7 +655,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
* emit a noisy warning on error, which won't stay unnoticed and * emit a noisy warning on error, which won't stay unnoticed and
* won't hose machine entirely. * won't hose machine entirely.
*/ */
err = device_reset(i2c_dev->dev);
WARN_ON_ONCE(err); WARN_ON_ONCE(err);
if (IS_DVC(i2c_dev)) if (IS_DVC(i2c_dev))
@ -1266,17 +1301,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
if (i2c_dev->dma_mode) { if (i2c_dev->dma_mode) {
if (i2c_dev->msg_read) { if (i2c_dev->msg_read) {
dma_sync_single_for_device(i2c_dev->dma_dev,
i2c_dev->dma_phys,
xfer_size, DMA_FROM_DEVICE);
err = tegra_i2c_dma_submit(i2c_dev, xfer_size); err = tegra_i2c_dma_submit(i2c_dev, xfer_size);
if (err) if (err)
return err; return err;
} else {
dma_sync_single_for_cpu(i2c_dev->dma_dev,
i2c_dev->dma_phys,
xfer_size, DMA_TO_DEVICE);
} }
} }
@ -1286,11 +1313,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
if (i2c_dev->dma_mode) { if (i2c_dev->dma_mode) {
memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE, memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE,
msg->buf, i2c_dev->msg_len); msg->buf, i2c_dev->msg_len);
dma_sync_single_for_device(i2c_dev->dma_dev,
i2c_dev->dma_phys,
xfer_size, DMA_TO_DEVICE);
err = tegra_i2c_dma_submit(i2c_dev, xfer_size); err = tegra_i2c_dma_submit(i2c_dev, xfer_size);
if (err) if (err)
return err; return err;
@ -1331,13 +1353,8 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) { if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE)
dma_sync_single_for_cpu(i2c_dev->dma_dev,
i2c_dev->dma_phys,
xfer_size, DMA_FROM_DEVICE);
memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, i2c_dev->msg_len); memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, i2c_dev->msg_len);
}
} }
time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete,
@ -1468,6 +1485,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = false, .has_slcg_override_reg = false,
.has_mst_fifo = false, .has_mst_fifo = false,
.has_mst_reset = false,
.quirks = &tegra_i2c_quirks, .quirks = &tegra_i2c_quirks,
.supports_bus_clear = false, .supports_bus_clear = false,
.has_apb_dma = true, .has_apb_dma = true,
@ -1492,6 +1510,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = false, .has_slcg_override_reg = false,
.has_mst_fifo = false, .has_mst_fifo = false,
.has_mst_reset = false,
.quirks = &tegra_i2c_quirks, .quirks = &tegra_i2c_quirks,
.supports_bus_clear = false, .supports_bus_clear = false,
.has_apb_dma = true, .has_apb_dma = true,
@ -1516,6 +1535,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = false, .has_slcg_override_reg = false,
.has_mst_fifo = false, .has_mst_fifo = false,
.has_mst_reset = false,
.quirks = &tegra_i2c_quirks, .quirks = &tegra_i2c_quirks,
.supports_bus_clear = true, .supports_bus_clear = true,
.has_apb_dma = true, .has_apb_dma = true,
@ -1540,6 +1560,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = true, .has_slcg_override_reg = true,
.has_mst_fifo = false, .has_mst_fifo = false,
.has_mst_reset = false,
.quirks = &tegra_i2c_quirks, .quirks = &tegra_i2c_quirks,
.supports_bus_clear = true, .supports_bus_clear = true,
.has_apb_dma = true, .has_apb_dma = true,
@ -1564,6 +1585,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = true, .has_slcg_override_reg = true,
.has_mst_fifo = false, .has_mst_fifo = false,
.has_mst_reset = false,
.quirks = &tegra_i2c_quirks, .quirks = &tegra_i2c_quirks,
.supports_bus_clear = true, .supports_bus_clear = true,
.has_apb_dma = true, .has_apb_dma = true,
@ -1588,6 +1610,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = true, .has_slcg_override_reg = true,
.has_mst_fifo = false, .has_mst_fifo = false,
.has_mst_reset = false,
.quirks = &tegra_i2c_quirks, .quirks = &tegra_i2c_quirks,
.supports_bus_clear = true, .supports_bus_clear = true,
.has_apb_dma = false, .has_apb_dma = false,
@ -1612,6 +1635,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_multi_master_mode = true, .has_multi_master_mode = true,
.has_slcg_override_reg = true, .has_slcg_override_reg = true,
.has_mst_fifo = true, .has_mst_fifo = true,
.has_mst_reset = true,
.quirks = &tegra194_i2c_quirks, .quirks = &tegra194_i2c_quirks,
.supports_bus_clear = true, .supports_bus_clear = true,
.has_apb_dma = false, .has_apb_dma = false,