mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-27 22:53:55 +08:00
i2c: tegra: Reorder location of functions in the code
Reorder location of functions in the code in order to have definition of functions closer to the place of the invocation. This change makes easier to navigate around the code and removes the need to have a prototype for tegra_i2c_init(). Reviewed-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Acked-by: Thierry Reding <treding@nvidia.com> Tested-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
This commit is contained in:
parent
55c52f16a0
commit
df384fa58a
@ -288,8 +288,6 @@ struct tegra_i2c_dev {
|
||||
bool is_curr_atomic_xfer;
|
||||
};
|
||||
|
||||
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev);
|
||||
|
||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned long reg)
|
||||
{
|
||||
@ -466,6 +464,56 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
|
||||
* block. This block is identical to the rest of the I2C blocks, except that
|
||||
* it only supports master mode, it has registers moved around, and it needs
|
||||
* some extra init to get it into I2C mode. The register moves are handled
|
||||
* by i2c_readl and i2c_writel
|
||||
*/
|
||||
static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
|
||||
val |= DVC_CTRL_REG3_SW_PROG;
|
||||
val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
|
||||
dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
|
||||
|
||||
val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
|
||||
val |= DVC_CTRL_REG1_INTR_EN;
|
||||
dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
|
||||
}
|
||||
|
||||
static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, 2) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_0);
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_TBUF, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STO, 7) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_THD_STA, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STA, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_1);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, 3) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, 8);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_0);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STO, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_THD_STA, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STA, 11);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_1);
|
||||
|
||||
value = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND;
|
||||
i2c_writel(i2c_dev, value, I2C_BUS_CLEAR_CNFG);
|
||||
|
||||
i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
|
||||
}
|
||||
|
||||
static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 mask, val, offset, reg_offset;
|
||||
@ -503,6 +551,164 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned long reg_offset;
|
||||
void __iomem *addr;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
if (i2c_dev->hw->has_config_load_reg) {
|
||||
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
|
||||
addr = i2c_dev->base + reg_offset;
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||
|
||||
if (i2c_dev->is_curr_atomic_xfer)
|
||||
err = readl_relaxed_poll_timeout_atomic(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
else
|
||||
err = readl_relaxed_poll_timeout(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
|
||||
if (err) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
"timeout waiting for config load\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 val;
|
||||
int err;
|
||||
u32 clk_divisor, clk_multiplier;
|
||||
u32 non_hs_mode;
|
||||
u32 tsu_thd;
|
||||
u8 tlow, thigh;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* want to fail the initialization completely because this may break
|
||||
* kernel boot up since voltage regulators use I2C. Hence, we will
|
||||
* emit a noisy warning on error, which won't stay unnoticed and
|
||||
* won't hose machine entirely.
|
||||
*/
|
||||
err = reset_control_reset(i2c_dev->rst);
|
||||
WARN_ON_ONCE(err);
|
||||
|
||||
if (i2c_dev->is_dvc)
|
||||
tegra_dvc_init(i2c_dev);
|
||||
|
||||
val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
|
||||
FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2);
|
||||
|
||||
if (i2c_dev->hw->has_multi_master_mode)
|
||||
val |= I2C_CNFG_MULTI_MASTER_MODE;
|
||||
|
||||
i2c_writel(i2c_dev, val, I2C_CNFG);
|
||||
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
|
||||
|
||||
if (i2c_dev->is_vi)
|
||||
tegra_i2c_vi_init(i2c_dev);
|
||||
|
||||
switch (i2c_dev->bus_clk_rate) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ:
|
||||
default:
|
||||
tlow = i2c_dev->hw->tlow_fast_fastplus_mode;
|
||||
thigh = i2c_dev->hw->thigh_fast_fastplus_mode;
|
||||
tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode;
|
||||
|
||||
if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
|
||||
non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode;
|
||||
else
|
||||
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
|
||||
break;
|
||||
|
||||
case 0 ... I2C_MAX_STANDARD_MODE_FREQ:
|
||||
tlow = i2c_dev->hw->tlow_std_mode;
|
||||
thigh = i2c_dev->hw->thigh_std_mode;
|
||||
tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
|
||||
non_hs_mode = i2c_dev->hw->clk_divisor_std_mode;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make sure clock divisor programmed correctly */
|
||||
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
|
||||
i2c_dev->hw->clk_divisor_hs_mode) |
|
||||
FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE, non_hs_mode);
|
||||
i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
|
||||
|
||||
if (i2c_dev->hw->has_interface_timing_reg) {
|
||||
val = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, thigh) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, tlow);
|
||||
i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
|
||||
}
|
||||
|
||||
/*
|
||||
* configure setup and hold times only when tsu_thd is non-zero.
|
||||
* otherwise, preserve the chip default values
|
||||
*/
|
||||
if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
|
||||
i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
|
||||
|
||||
clk_multiplier = tlow + thigh + 2;
|
||||
clk_multiplier *= non_hs_mode + 1;
|
||||
|
||||
err = clk_set_rate(i2c_dev->div_clk,
|
||||
i2c_dev->bus_clk_rate * clk_multiplier);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to set div-clk rate: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!i2c_dev->is_dvc && !i2c_dev->is_vi) {
|
||||
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
|
||||
|
||||
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
|
||||
i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
|
||||
i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
|
||||
i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
|
||||
}
|
||||
|
||||
err = tegra_i2c_flush_fifos(i2c_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
|
||||
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
|
||||
|
||||
err = tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 cnfg;
|
||||
|
||||
/*
|
||||
* NACK interrupt is generated before the I2C controller generates
|
||||
* the STOP condition on the bus. So wait for 2 clock periods
|
||||
* before disabling the controller so that the STOP condition has
|
||||
* been delivered properly.
|
||||
*/
|
||||
udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate));
|
||||
|
||||
cnfg = i2c_readl(i2c_dev, I2C_CNFG);
|
||||
if (cnfg & I2C_CNFG_PACKET_MODE_EN)
|
||||
i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
|
||||
|
||||
return tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
}
|
||||
|
||||
static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 val;
|
||||
@ -632,256 +838,6 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
|
||||
* block. This block is identical to the rest of the I2C blocks, except that
|
||||
* it only supports master mode, it has registers moved around, and it needs
|
||||
* some extra init to get it into I2C mode. The register moves are handled
|
||||
* by i2c_readl and i2c_writel
|
||||
*/
|
||||
static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
|
||||
val |= DVC_CTRL_REG3_SW_PROG;
|
||||
val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
|
||||
dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
|
||||
|
||||
val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
|
||||
val |= DVC_CTRL_REG1_INTR_EN;
|
||||
dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_default_state(i2c_dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_bulk_enable(i2c_dev->nclocks, i2c_dev->clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* VI I2C device is attached to VE power domain which goes through
|
||||
* power ON/OFF during PM runtime resume/suspend. So, controller
|
||||
* should go through reset and need to re-initialize after power
|
||||
* domain ON.
|
||||
*/
|
||||
if (i2c_dev->is_vi) {
|
||||
ret = tegra_i2c_init(i2c_dev);
|
||||
if (ret)
|
||||
goto disable_clocks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clocks:
|
||||
clk_bulk_disable(i2c_dev->nclocks, i2c_dev->clocks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
clk_bulk_disable(i2c_dev->nclocks, i2c_dev->clocks);
|
||||
|
||||
return pinctrl_pm_select_idle_state(i2c_dev->dev);
|
||||
}
|
||||
|
||||
static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned long reg_offset;
|
||||
void __iomem *addr;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
if (i2c_dev->hw->has_config_load_reg) {
|
||||
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
|
||||
addr = i2c_dev->base + reg_offset;
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||
|
||||
if (i2c_dev->is_curr_atomic_xfer)
|
||||
err = readl_relaxed_poll_timeout_atomic(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
else
|
||||
err = readl_relaxed_poll_timeout(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
|
||||
if (err) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
"timeout waiting for config load\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, 2) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_0);
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_TBUF, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STO, 7) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_THD_STA, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STA, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_1);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, 3) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, 8);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_0);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STO, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_THD_STA, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STA, 11);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_1);
|
||||
|
||||
value = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND;
|
||||
i2c_writel(i2c_dev, value, I2C_BUS_CLEAR_CNFG);
|
||||
|
||||
i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
|
||||
}
|
||||
|
||||
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 val;
|
||||
int err;
|
||||
u32 clk_divisor, clk_multiplier;
|
||||
u32 non_hs_mode;
|
||||
u32 tsu_thd;
|
||||
u8 tlow, thigh;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* want to fail the initialization completely because this may break
|
||||
* kernel boot up since voltage regulators use I2C. Hence, we will
|
||||
* emit a noisy warning on error, which won't stay unnoticed and
|
||||
* won't hose machine entirely.
|
||||
*/
|
||||
err = reset_control_reset(i2c_dev->rst);
|
||||
WARN_ON_ONCE(err);
|
||||
|
||||
if (i2c_dev->is_dvc)
|
||||
tegra_dvc_init(i2c_dev);
|
||||
|
||||
val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
|
||||
FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2);
|
||||
|
||||
if (i2c_dev->hw->has_multi_master_mode)
|
||||
val |= I2C_CNFG_MULTI_MASTER_MODE;
|
||||
|
||||
i2c_writel(i2c_dev, val, I2C_CNFG);
|
||||
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
|
||||
|
||||
if (i2c_dev->is_vi)
|
||||
tegra_i2c_vi_init(i2c_dev);
|
||||
|
||||
switch (i2c_dev->bus_clk_rate) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ:
|
||||
default:
|
||||
tlow = i2c_dev->hw->tlow_fast_fastplus_mode;
|
||||
thigh = i2c_dev->hw->thigh_fast_fastplus_mode;
|
||||
tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode;
|
||||
|
||||
if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
|
||||
non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode;
|
||||
else
|
||||
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
|
||||
break;
|
||||
|
||||
case 0 ... I2C_MAX_STANDARD_MODE_FREQ:
|
||||
tlow = i2c_dev->hw->tlow_std_mode;
|
||||
thigh = i2c_dev->hw->thigh_std_mode;
|
||||
tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
|
||||
non_hs_mode = i2c_dev->hw->clk_divisor_std_mode;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make sure clock divisor programmed correctly */
|
||||
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
|
||||
i2c_dev->hw->clk_divisor_hs_mode) |
|
||||
FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE, non_hs_mode);
|
||||
i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
|
||||
|
||||
if (i2c_dev->hw->has_interface_timing_reg) {
|
||||
val = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, thigh) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, tlow);
|
||||
i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
|
||||
}
|
||||
|
||||
/*
|
||||
* configure setup and hold times only when tsu_thd is non-zero.
|
||||
* otherwise, preserve the chip default values
|
||||
*/
|
||||
if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
|
||||
i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
|
||||
|
||||
clk_multiplier = tlow + thigh + 2;
|
||||
clk_multiplier *= non_hs_mode + 1;
|
||||
|
||||
err = clk_set_rate(i2c_dev->div_clk,
|
||||
i2c_dev->bus_clk_rate * clk_multiplier);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to set div-clk rate: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!i2c_dev->is_dvc && !i2c_dev->is_vi) {
|
||||
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
|
||||
|
||||
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
|
||||
i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
|
||||
i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
|
||||
i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
|
||||
}
|
||||
|
||||
err = tegra_i2c_flush_fifos(i2c_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
|
||||
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
|
||||
|
||||
err = tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 cnfg;
|
||||
|
||||
/*
|
||||
* NACK interrupt is generated before the I2C controller generates
|
||||
* the STOP condition on the bus. So wait for 2 clock periods
|
||||
* before disabling the controller so that the STOP condition has
|
||||
* been delivered properly.
|
||||
*/
|
||||
udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate));
|
||||
|
||||
cnfg = i2c_readl(i2c_dev, I2C_CNFG);
|
||||
if (cnfg & I2C_CNFG_PACKET_MODE_EN)
|
||||
i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
|
||||
|
||||
return tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
||||
{
|
||||
u32 status;
|
||||
@ -1418,27 +1374,6 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct device_node *np = i2c_dev->dev->of_node;
|
||||
int ret;
|
||||
bool multi_mode;
|
||||
|
||||
ret = of_property_read_u32(np, "clock-frequency",
|
||||
&i2c_dev->bus_clk_rate);
|
||||
if (ret)
|
||||
i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */
|
||||
|
||||
multi_mode = of_property_read_bool(np, "multi-master");
|
||||
i2c_dev->is_multimaster_mode = multi_mode;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
|
||||
i2c_dev->is_dvc = true;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
|
||||
i2c_dev->is_vi = true;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
.master_xfer = tegra_i2c_xfer,
|
||||
.master_xfer_atomic = tegra_i2c_xfer_atomic,
|
||||
@ -1644,6 +1579,27 @@ static const struct of_device_id tegra_i2c_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
|
||||
|
||||
static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct device_node *np = i2c_dev->dev->of_node;
|
||||
int ret;
|
||||
bool multi_mode;
|
||||
|
||||
ret = of_property_read_u32(np, "clock-frequency",
|
||||
&i2c_dev->bus_clk_rate);
|
||||
if (ret)
|
||||
i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */
|
||||
|
||||
multi_mode = of_property_read_bool(np, "multi-master");
|
||||
i2c_dev->is_multimaster_mode = multi_mode;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
|
||||
i2c_dev->is_dvc = true;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
|
||||
i2c_dev->is_vi = true;
|
||||
}
|
||||
|
||||
static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
int err;
|
||||
@ -1819,6 +1775,48 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_default_state(i2c_dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_bulk_enable(i2c_dev->nclocks, i2c_dev->clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* VI I2C device is attached to VE power domain which goes through
|
||||
* power ON/OFF during PM runtime resume/suspend. So, controller
|
||||
* should go through reset and need to re-initialize after power
|
||||
* domain ON.
|
||||
*/
|
||||
if (i2c_dev->is_vi) {
|
||||
ret = tegra_i2c_init(i2c_dev);
|
||||
if (ret)
|
||||
goto disable_clocks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clocks:
|
||||
clk_bulk_disable(i2c_dev->nclocks, i2c_dev->clocks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
clk_bulk_disable(i2c_dev->nclocks, i2c_dev->clocks);
|
||||
|
||||
return pinctrl_pm_select_idle_state(i2c_dev->dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
Loading…
Reference in New Issue
Block a user