summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNaveen Krishna Ch <ch.naveen@samsung.com>2014-04-28 14:29:58 +0530
committerHyungwon Hwang <human.hwang@samsung.com>2014-12-17 16:18:04 +0900
commitdb92996a5fe9da929a11dcc4cc97e17fbf38623b (patch)
tree73032c99937ac0937cbc10c2fce764f225d8fb82 /drivers
parent1d597a2e4ea0bd4e22f0845bc30eca30585907b3 (diff)
downloadlinux-3.10-db92996a5fe9da929a11dcc4cc97e17fbf38623b.tar.gz
linux-3.10-db92996a5fe9da929a11dcc4cc97e17fbf38623b.tar.bz2
linux-3.10-db92996a5fe9da929a11dcc4cc97e17fbf38623b.zip
i2c: exynos5: add support for HSI2C on Exynos5260 SoC
HSI2C module on Exynos5260 differs from current modules in following ways: 1. HSI2C on Exynos5260 has fifo_depth of 16bytes 2. Module needs to be reset as a part of init sequence. Hence, Following changes are involved. 1. Add a new compatible string and Updates the Documentation dt bindings. 2. Introduce a variant struct to support the changes in H/W 3. Reset the module during init. Thus, bringing the module back to default state irrespective of what firmware did with it. Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c67
1 files changed, 55 insertions, 12 deletions
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 29f4b6615b3..398ea50cb48 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -77,12 +77,6 @@
#define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4)
#define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16)
-/* As per user manual FIFO max depth is 64bytes */
-#define HSI2C_FIFO_MAX 0x40
-/* default trigger levels for Tx and Rx FIFOs */
-#define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30)
-#define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10)
-
/* I2C_TRAILING_CTL Register bits */
#define HSI2C_TRAILING_COUNT (0xf)
@@ -184,14 +178,54 @@ struct exynos5_i2c {
* 2. Fast speed upto 1Mbps
*/
int speed_mode;
+
+ /* Version of HS-I2C Hardware */
+ struct exynos_hsi2c_variant *variant;
+};
+
+/**
+ * struct exynos_hsi2c_variant - platform specific HSI2C driver data
+ * @fifo_depth: the fifo depth supported by the HSI2C module
+ *
+ * Specifies platform specific configuration of HSI2C module.
+ * Note: A structure for driver specific platform data is used for future
+ * expansion of its usage.
+ */
+struct exynos_hsi2c_variant {
+ unsigned int fifo_depth;
+};
+
+static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {
+ .fifo_depth = 64,
+};
+
+static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {
+ .fifo_depth = 16,
};
static const struct of_device_id exynos5_i2c_match[] = {
- { .compatible = "samsung,exynos5-hsi2c" },
- {},
+ {
+ .compatible = "samsung,exynos5-hsi2c",
+ .data = &exynos5250_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos5250-hsi2c",
+ .data = &exynos5250_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos5260-hsi2c",
+ .data = &exynos5260_hsi2c_data
+ }, {},
};
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
+static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant
+ (struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_node(exynos5_i2c_match, pdev->dev.of_node);
+ return (struct exynos_hsi2c_variant *)match->data;
+}
+
static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
{
writel(readl(i2c->regs + HSI2C_INT_STATUS),
@@ -416,7 +450,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
fifo_level = HSI2C_TX_FIFO_LVL(fifo_status);
- len = HSI2C_FIFO_MAX - fifo_level;
+ len = i2c->variant->fifo_depth - fifo_level;
if (len > (i2c->msg->len - i2c->msg_ptr))
len = i2c->msg->len - i2c->msg_ptr;
@@ -484,6 +518,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
u32 i2c_auto_conf = 0;
u32 fifo_ctl;
unsigned long flags;
+ unsigned short trig_lvl;
i2c_ctl = readl(i2c->regs + HSI2C_CTL);
i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON);
@@ -494,13 +529,19 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
i2c_auto_conf = HSI2C_READ_WRITE;
- fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL);
+ trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
+ (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len;
+ fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl);
+
int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN |
HSI2C_INT_TRAILING_EN);
} else {
i2c_ctl |= HSI2C_TXCHON;
- fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL);
+ trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
+ (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len;
+ fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_lvl);
+
int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN;
}
@@ -692,7 +733,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
if (ret)
goto err_clk;
- exynos5_i2c_init(i2c);
+ i2c->variant = exynos5_i2c_get_variant(pdev);
+
+ exynos5_i2c_reset(i2c);
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {