diff mbox

[RESEND,2/4] i2c: i2c-bcm-kona: Add support for high-speed mode

Message ID 1381960909-1735-3-git-send-email-tim.kryger@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Tim Kryger Oct. 16, 2013, 10:01 p.m. UTC
Add support for I2C high-speed mode (3.4 MHz).

Signed-off-by: Tim Kryger <tim.kryger@linaro.org>
Reviewed-by: Matt Porter <matt.porter@linaro.org>
Reviewed-by: Markus Mayer <markus.mayer@linaro.org>
---
 drivers/i2c/busses/i2c-bcm-kona.c | 116 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

Comments

Wolfram Sang Nov. 1, 2013, 1:08 p.m. UTC | #1
On Wed, Oct 16, 2013 at 03:01:47PM -0700, Tim Kryger wrote:
> Add support for I2C high-speed mode (3.4 MHz).
> 
> Signed-off-by: Tim Kryger <tim.kryger@linaro.org>
> Reviewed-by: Matt Porter <matt.porter@linaro.org>
> Reviewed-by: Markus Mayer <markus.mayer@linaro.org>

Mostly good as well:

> +enum hs_bus_speed_index {
> +	BCM_SPD_3P4MHZ = 0,
> +};

I just realized that you should update both patches to add the supported
bus speeds to the binding documentation.

Thanks,

   Wolfram
Tim Kryger Nov. 7, 2013, 7:57 p.m. UTC | #2
On Fri, Nov 1, 2013 at 6:08 AM, Wolfram Sang <wsa@the-dreams.de> wrote:
> On Wed, Oct 16, 2013 at 03:01:47PM -0700, Tim Kryger wrote:
>> Add support for I2C high-speed mode (3.4 MHz).
>>
>> Signed-off-by: Tim Kryger <tim.kryger@linaro.org>
>> Reviewed-by: Matt Porter <matt.porter@linaro.org>
>> Reviewed-by: Markus Mayer <markus.mayer@linaro.org>
>
> Mostly good as well:
>
>> +enum hs_bus_speed_index {
>> +     BCM_SPD_3P4MHZ = 0,
>> +};
>
> I just realized that you should update both patches to add the supported
> bus speeds to the binding documentation.

While the bus speed property is really a configuration parameter (and
not a true description of of the hardware) it seems improper to put
driver specific details into the binding document.

Please let me know how you would like me to proceed.

I should mention that I plan to break out the binding into its own
patch as this seems to be the latest best practice just in case that
influences your decision.

Thanks,
Tim Kryger
Wolfram Sang Nov. 7, 2013, 8:13 p.m. UTC | #3
> While the bus speed property is really a configuration parameter (and
> not a true description of of the hardware) it seems improper to put
> driver specific details into the binding document.

OK. Then please change the error message for unsupported bus speeds to
contain the supported ones. I don't think it is good practice to force
users to look into the sourcecode to find this information.

Regards,

   Wolfram
Tim Kryger Nov. 7, 2013, 8:16 p.m. UTC | #4
On Thu, Nov 7, 2013 at 12:13 PM, Wolfram Sang <wsa@the-dreams.de> wrote:

> OK. Then please change the error message for unsupported bus speeds to
> contain the supported ones. I don't think it is good practice to force
> users to look into the sourcecode to find this information.

That works for me.  Thanks.

-Tim
diff mbox

Patch

diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 2936acf..458714f 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -77,6 +77,9 @@ 
 
 #define HSTIM_OFFSET				0x00000058
 #define HSTIM_HS_MODE_MASK			0x00008000
+#define HSTIM_HS_HOLD_SHIFT			10
+#define HSTIM_HS_HIGH_PHASE_SHIFT		5
+#define HSTIM_HS_SETUP_SHIFT			0
 
 #define PADCTL_OFFSET				0x0000005c
 #define PADCTL_PAD_OUT_EN_MASK			0x00000004
@@ -91,6 +94,9 @@ 
 #define MAX_TX_FIFO_SIZE		64U /* bytes */
 
 #define STD_EXT_CLK_FREQ		13000000UL
+#define HS_EXT_CLK_FREQ			104000000UL
+
+#define MASTERCODE			0x08 /* Mastercodes are 0000_1xxxb */
 
 #define I2C_TIMEOUT			100 /* msecs */
 
@@ -108,6 +114,10 @@  enum bus_speed_index {
 	BCM_SPD_1MHZ,
 };
 
+enum hs_bus_speed_index {
+	BCM_SPD_3P4MHZ = 0,
+};
+
 /* Internal divider settings for standard mode, fast mode and fast mode plus */
 struct bus_speed_cfg {
 	uint8_t time_m;		/* Number of cycles for setup time */
@@ -118,12 +128,30 @@  struct bus_speed_cfg {
 	uint8_t time_div;	/* Post-prescale divider */
 };
 
+/* Internal divider settings for high-speed mode */
+struct hs_bus_speed_cfg {
+	uint8_t hs_hold;	/* Number of clock cycles SCL stays low until
+				   the end of bit period */
+	uint8_t hs_high_phase;	/* Number of clock cycles SCL stays high
+				   before it falls */
+	uint8_t hs_setup;	/* Number of clock cycles SCL stays low
+				   before it rises  */
+	uint8_t prescale;	/* Prescale divider */
+	uint8_t time_p;		/* Timing coefficient */
+	uint8_t no_div;		/* Disable clock divider */
+	uint8_t time_div;	/* Post-prescale divider */
+};
+
 static const struct bus_speed_cfg std_cfg_table[] = {
 	[BCM_SPD_100K] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02},
 	[BCM_SPD_400K] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02},
 	[BCM_SPD_1MHZ] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03},
 };
 
+static const struct hs_bus_speed_cfg hs_cfg_table[] = {
+	[BCM_SPD_3P4MHZ] = {0x01, 0x08, 0x14, 0x00, 0x06, 0x01, 0x00},
+};
+
 struct bcm_kona_i2c_dev {
 	/* Pointer to linux device struct */
 	struct device *device;
@@ -137,6 +165,9 @@  struct bcm_kona_i2c_dev {
 	/* Standard Speed configuration */
 	const struct bus_speed_cfg *std_cfg;
 
+	/* High Speed configuration (if applicable) */
+	const struct hs_bus_speed_cfg *hs_cfg;
+
 	/* Linux I2C adapter struct */
 	struct i2c_adapter adapter;
 
@@ -520,6 +551,72 @@  static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev)
 	       dev->base + CLKEN_OFFSET);
 }
 
+static void bcm_kona_i2c_config_timing_hs(struct bcm_kona_i2c_dev *dev)
+{
+	writel((dev->hs_cfg->prescale << TIM_PRESCALE_SHIFT) |
+	       (dev->hs_cfg->time_p << TIM_P_SHIFT) |
+	       (dev->hs_cfg->no_div << TIM_NO_DIV_SHIFT) |
+	       (dev->hs_cfg->time_div << TIM_DIV_SHIFT),
+	       dev->base + TIM_OFFSET);
+
+	writel((dev->hs_cfg->hs_hold << HSTIM_HS_HOLD_SHIFT) |
+	       (dev->hs_cfg->hs_high_phase << HSTIM_HS_HIGH_PHASE_SHIFT) |
+	       (dev->hs_cfg->hs_setup << HSTIM_HS_SETUP_SHIFT),
+	       dev->base + HSTIM_OFFSET);
+
+	writel(readl(dev->base + HSTIM_OFFSET) | HSTIM_HS_MODE_MASK,
+	       dev->base + HSTIM_OFFSET);
+}
+
+static int bcm_kona_i2c_switch_to_hs(struct bcm_kona_i2c_dev *dev)
+{
+	int rc;
+
+	/* Send mastercode at standard speed */
+	rc = bcm_kona_i2c_write_byte(dev, MASTERCODE, 1);
+	if (rc < 0) {
+		pr_err("High speed handshake failed\n");
+		return rc;
+	}
+
+	/* Configure external clock to higher frequency */
+	rc = clk_set_rate(dev->external_clk, HS_EXT_CLK_FREQ);
+	if (rc) {
+		dev_err(dev->device, "%s: clk_set_rate returned %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	/* Reconfigure internal dividers */
+	bcm_kona_i2c_config_timing_hs(dev);
+
+	/* Send a restart command */
+	rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
+	if (rc < 0) {
+		dev_err(dev->device,
+		"High speed restart command failed rc = %d\n", rc);
+	}
+
+	return rc;
+}
+
+static int bcm_kona_i2c_switch_to_std(struct bcm_kona_i2c_dev *dev)
+{
+	int rc;
+
+	/* Reconfigure internal dividers */
+	bcm_kona_i2c_config_timing(dev);
+
+	/* Configure external clock to lower frequency */
+	rc = clk_set_rate(dev->external_clk, STD_EXT_CLK_FREQ);
+	if (rc) {
+		dev_err(dev->device, "%s: clk_set_rate returned %d\n",
+			__func__, rc);
+	}
+
+	return rc;
+}
+
 /* Master transfer function */
 static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter,
 			     struct i2c_msg msgs[], int num)
@@ -551,6 +648,13 @@  static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter,
 		goto xfer_disable_pad;
 	}
 
+	/* Switch to high speed if applicable */
+	if (dev->hs_cfg) {
+		rc = bcm_kona_i2c_switch_to_hs(dev);
+		if (rc < 0)
+			goto xfer_send_stop;
+	}
+
 	/* Loop through all messages */
 	for (i = 0; i < num; i++) {
 		pmsg = &msgs[i];
@@ -598,6 +702,13 @@  xfer_send_stop:
 	/* Send a STOP command */
 	bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP);
 
+	/* Return from high speed if applicable */
+	if (dev->hs_cfg) {
+		int hs_rc = bcm_kona_i2c_switch_to_std(dev);
+		if (hs_rc)
+			rc = hs_rc;
+	}
+
 xfer_disable_pad:
 	/* Disable pad output */
 	writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
@@ -642,6 +753,11 @@  static int bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev)
 	case 1000000:
 		dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ];
 		break;
+	case 3400000:
+		/* Send mastercode at 100k */
+		dev->std_cfg = &std_cfg_table[BCM_SPD_100K];
+		dev->hs_cfg = &hs_cfg_table[BCM_SPD_3P4MHZ];
+		break;
 	default:
 		pr_err("%d hz bus speed not supported\n", bus_speed);
 		return -EINVAL;