summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaveh Jalali <caveh@chromium.org>2021-09-18 00:19:11 -0700
committerCommit Bot <commit-bot@chromium.org>2021-09-25 03:06:22 +0000
commit1808a11f2a43a665aa88a662eef96028db5da6e5 (patch)
tree1d19812e55d5f332271a3ae7ca4d45c2d4a0e361
parent7d96d1326fe160c373d1deb0a017611f3f6baf74 (diff)
downloadchrome-ec-1808a11f2a43a665aa88a662eef96028db5da6e5.tar.gz
npcx/i2c: Refactor i2c_freq_changed
This splits the implementation of i2c_freq_changed() into a per-port worker function and a top-level iterator function. This change makes i2c_port_set_freq() available to set a port's I2C speed. BRANCH=none BUG=b:201039003 TEST=with follow-on patches, switched I2C bus speed between 400 kHz and 1 MHz. Change-Id: Ifb5613ac3a59cbd64f01f3a396f978db5e77d9f1 Signed-off-by: Caveh Jalali <caveh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3170291 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--chip/npcx/i2c.c160
1 files changed, 86 insertions, 74 deletions
diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c
index 0528a7cca8..ccc3be554d 100644
--- a/chip/npcx/i2c.c
+++ b/chip/npcx/i2c.c
@@ -1017,90 +1017,103 @@ int i2c_raw_get_sda(int port)
}
/*****************************************************************************/
-/* Hooks */
-static void i2c_freq_changed(void)
-{
- int freq, i, j;
- for (i = 0; i < i2c_ports_used; i++) {
- int bus_freq = i2c_ports[i].kbps;
- int ctrl = i2c_port_to_controller(i2c_ports[i].port);
- int scl_freq;
+static void i2c_port_set_freq(const int ctrl, const int bus_freq)
+{
+ int freq, j;
+ int scl_freq;
+ const struct i2c_timing *pTiming;
+ int i2c_timing_used;
#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
- /*
- * SMB0/1/4/5/6/7 use APB3 clock
- * SMB2/3 use APB2 clock
- */
- freq = (ctrl < 2 || ctrl > 3) ?
- clock_get_apb3_freq() : clock_get_apb2_freq();
+ /*
+ * SMB0/1/4/5/6/7 use APB3 clock
+ * SMB2/3 use APB2 clock
+ */
+ freq = (ctrl < 2 || ctrl > 3) ?
+ clock_get_apb3_freq() : clock_get_apb2_freq();
#else /* CHIP_FAMILY_NPCX5 */
- /*
- * SMB0/1 use core clock
- * SMB2/3 use APB2 clock
- */
- freq = (ctrl < 2) ? clock_get_freq() : clock_get_apb2_freq();
+ /*
+ * SMB0/1 use core clock
+ * SMB2/3 use APB2 clock
+ */
+ freq = (ctrl < 2) ? clock_get_freq() : clock_get_apb2_freq();
#endif
- /*
- * Set SCL frequency by formula:
- * tSCL = 4 * SCLFRQ * tCLK
- * fSCL = fCLK / (4*SCLFRQ)
- * SCLFRQ = ceil(fCLK/(4*fSCL))
- */
- scl_freq = DIV_ROUND_UP(freq, bus_freq*4000); /* Unit in bps */
-
- /* Normal mode if i2c freq is under 100kHz */
- if (bus_freq <= 100) {
- /* Set divider value of SCL */
- SET_FIELD(NPCX_SMBCTL2(ctrl), NPCX_SMBCTL2_SCLFRQ7_FIELD
- , (scl_freq & 0x7F));
- SET_FIELD(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_SCLFRQ2_FIELD
- , (scl_freq >> 7));
- } else {
- const struct i2c_timing *pTiming;
- int i2c_timing_used;
+ /*
+ * Set SCL frequency by formula:
+ * tSCL = 4 * SCLFRQ * tCLK
+ * fSCL = fCLK / (4*SCLFRQ)
+ * SCLFRQ = ceil(fCLK/(4*fSCL))
+ */
+ scl_freq = DIV_ROUND_UP(freq, bus_freq*4000); /* Unit in bps */
+
+ /* Normal mode if I2C freq is under 100kHz */
+ if (bus_freq <= 100) {
+ /* Set divider value of SCL */
+ SET_FIELD(NPCX_SMBCTL2(ctrl), NPCX_SMBCTL2_SCLFRQ7_FIELD,
+ (scl_freq & 0x7F));
+ SET_FIELD(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_SCLFRQ2_FIELD,
+ (scl_freq >> 7));
+ return;
+ }
- /* use Fast Mode */
- SET_BIT(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_400K);
- /*
- * Set SCLH(L)T and hold-time directly for best i2c
- * timing condition for all source clocks. Please refer
- * Section 7.5.9 "SMBus Timing - Fast Mode" for detail.
- */
- if (bus_freq == 400) {
- pTiming = i2c_400k_timings;
- i2c_timing_used = i2c_400k_timing_used;
- } else if (bus_freq == 1000) {
- pTiming = i2c_1m_timings;
- i2c_timing_used = i2c_1m_timing_used;
- } else {
- /* Set value from formula */
- NPCX_SMBSCLLT(ctrl) = scl_freq;
- NPCX_SMBSCLHT(ctrl) = scl_freq;
- cprints(CC_I2C,
- "Warning: Use 400K or 1MHz for better timing of I2c %d",
- ctrl);
- continue;
- }
+ /* use Fast Mode */
+ SET_BIT(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_400K);
+ /*
+ * Set SCLH(L)T and hold-time directly for best I2C
+ * timing condition for all source clocks. Please refer
+ * Section 7.5.9 "SMBus Timing - Fast Mode" for detail.
+ */
+ if (bus_freq == 400) {
+ pTiming = i2c_400k_timings;
+ i2c_timing_used = i2c_400k_timing_used;
+ } else if (bus_freq == 1000) {
+ pTiming = i2c_1m_timings;
+ i2c_timing_used = i2c_1m_timing_used;
+ } else {
+ /* Set value from formula */
+ NPCX_SMBSCLLT(ctrl) = scl_freq;
+ NPCX_SMBSCLHT(ctrl) = scl_freq;
+ cprints(CC_I2C,
+ "Warning: I2C %d: Use 400kHz or 1MHz for better timing",
+ ctrl);
+ return;
+ }
- for (j = 0; j < i2c_timing_used; j++, pTiming++) {
- if (pTiming->clock == (freq/SECOND)) {
- /* Set SCLH(L)T and hold-time */
- NPCX_SMBSCLLT(ctrl) = pTiming->k1/2;
- NPCX_SMBSCLHT(ctrl) = pTiming->k2/2;
- SET_FIELD(NPCX_SMBCTL4(ctrl),
- NPCX_SMBCTL4_HLDT_FIELD, pTiming->HLDT);
- break;
- }
- }
- if (j == i2c_timing_used)
- cprints(CC_I2C,
- "Error: Please make sure src clock of i2c %d is supported",
- ctrl);
+ for (j = 0; j < i2c_timing_used; j++, pTiming++) {
+ if (pTiming->clock == (freq/SECOND)) {
+ /* Set SCLH(L)T and hold-time */
+ NPCX_SMBSCLLT(ctrl) = pTiming->k1/2;
+ NPCX_SMBSCLHT(ctrl) = pTiming->k2/2;
+ SET_FIELD(NPCX_SMBCTL4(ctrl),
+ NPCX_SMBCTL4_HLDT_FIELD, pTiming->HLDT);
+ break;
}
}
+ if (j == i2c_timing_used)
+ cprints(CC_I2C, "Error: I2C %d: src clk %d not supported",
+ ctrl, freq / SECOND);
}
+
+/* Hooks */
+
+static void i2c_freq_changed(void)
+{
+ int i;
+
+ for (i = 0; i < i2c_ports_used; i++) {
+ const struct i2c_port_t *p;
+ int ctrl;
+
+ p = &i2c_ports[i];
+ ctrl = i2c_port_to_controller(p->port);
+ if (ctrl < 0)
+ continue;
+ i2c_port_set_freq(ctrl, p->kbps);
+ }
+}
+
DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);
void i2c_init(void)
@@ -1147,4 +1160,3 @@ void i2c_init(void)
i2c_init_bus(ctrl);
}
}
-