From patchwork Fri Mar 20 00:57:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Nemirovsky X-Patchwork-Id: 1258557 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cortina-access.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=CortinaAccess.onmicrosoft.com header.i=@CortinaAccess.onmicrosoft.com header.a=rsa-sha256 header.s=selector2-CortinaAccess-onmicrosoft-com header.b=uCoO3h9s; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48k54V5bdpz9sPF for ; Fri, 20 Mar 2020 11:58:34 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7DED081750; Fri, 20 Mar 2020 01:57:55 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=cortina-access.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=CortinaAccess.onmicrosoft.com header.i=@CortinaAccess.onmicrosoft.com header.b="uCoO3h9s"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 0883181552; Fri, 20 Mar 2020 01:57:43 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,FORGED_SPF_HELO,MSGID_FROM_MTA_HEADER,SPF_HELO_PASS, URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from APC01-HK2-obe.outbound.protection.outlook.com (mail-hk2apc01on0601.outbound.protection.outlook.com [IPv6:2a01:111:f400:febc::601]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 53687812B1 for ; Fri, 20 Mar 2020 01:57:37 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=cortina-access.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=Alex.Nemirovsky@cortina-access.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GBr8FhIB3ZVdZ9n3wlSbf3nIFleTSIcPWviMNIcR/ULzt4ATUK7QgXlyuV4S7I2HjUbIxj8UVyGdnN8RJBwd7dNWNH5KfbLzXOFyuxky4LtiO6WVMIbmm2YVL8YdO+WQcpdRLMqHiFzO/GqjnXjbYLHDvupF/bBZuBRFPIhbZVnpX4XglKs1SctmZFJyR5UK+hg6tiKV0KmG+xjSKBnteTNxOOQ822gJ+BgBvgJIDVsevBbeAoVQLV20XymkMBnn7kYEzOIBfPukPLt6bqjEwj04/oHrdsjk/SYv0bmvjy3wNxwrJwkUZvWl6C5lzHzL1oUocVwpd1HEGi/Vpe7VXg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=zTAj1XQyyGvB5Zm3tq3FY22WsUJFd0y9nEZygjhK/ww=; b=PfDqQgfZ7qBJJpNsWXKR5vTqaxOT2k2GOtvm8MhkYh0uGa/2oaiD6cUAWStF2f0e4BNX/0SYNynfrezOBjAouKBXJR2JZEIrLpcWFIAVmlr0yqNKLM5aPduzLMXEWhA/QmOwxaH9WlQWUdRjwrRPYApUPFUIBr0zWuPdCJEN7Qt6JpwSJ38wNQJ05bRWUqbpwDpu3tTy0SBbID8FXUaAiWi5N6vz2Qlz7g2rWyzvP63k1a/Q8Utom9QP3B+FmFKNDF7cXaCtq1Y4sfzzBDivBa9WMrVBh6MpDH1FVdS70xOzuahfNqTzUG5ME6Sty3pzxbQ94ULpPtUqvBdok5IPxg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=cortina-access.com; dmarc=pass action=none header.from=cortina-access.com; dkim=pass header.d=cortina-access.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=CortinaAccess.onmicrosoft.com; s=selector2-CortinaAccess-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=zTAj1XQyyGvB5Zm3tq3FY22WsUJFd0y9nEZygjhK/ww=; b=uCoO3h9srsznxO7p71Q8hZgZxLfnJ/YCRPlF5QZtIB0AcsdD6SPvJ9wu5Q+lW4i34hJdzWSU9XIxAbg0j9PIF8kmZ2Kay5ZPTXasiSEC8Ec1lYAvpqD4hSIKyWm6zz/DfJd+tQv5pA3VEY+bEcvwaWDIgx1iqZnoDvri6U1d1lY= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Alex.Nemirovsky@cortina-access.com; Received: from PU1PR01MB1964.apcprd01.prod.exchangelabs.com (10.170.191.16) by PU1PR01MB1882.apcprd01.prod.exchangelabs.com (10.170.190.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2835.19; Fri, 20 Mar 2020 00:57:35 +0000 Received: from PU1PR01MB1964.apcprd01.prod.exchangelabs.com ([fe80::8505:cc66:dbab:cdf4]) by PU1PR01MB1964.apcprd01.prod.exchangelabs.com ([fe80::8505:cc66:dbab:cdf4%7]) with mapi id 15.20.2814.021; Fri, 20 Mar 2020 00:57:35 +0000 From: Alex Nemirovsky To: u-boot@lists.denx.de Cc: Arthur Li , Alex Nemirovsky , Heiko Schocher Subject: [PATCH v2 3/8] i2c: i2c-cortina: added CAxxxx I2C support Date: Thu, 19 Mar 2020 17:57:04 -0700 Message-Id: <1584665829-4881-4-git-send-email-alex.nemirovsky@cortina-access.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584665829-4881-1-git-send-email-alex.nemirovsky@cortina-access.com> References: <1584665829-4881-1-git-send-email-alex.nemirovsky@cortina-access.com> X-ClientProxiedBy: MWHPR12CA0065.namprd12.prod.outlook.com (2603:10b6:300:103::27) To PU1PR01MB1964.apcprd01.prod.exchangelabs.com (2603:1096:803:1e::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from smok.hrh.localdomain (70.58.207.205) by MWHPR12CA0065.namprd12.prod.outlook.com (2603:10b6:300:103::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.20.2835.18 via Frontend Transport; Fri, 20 Mar 2020 00:57:33 +0000 X-Mailer: git-send-email 2.7.4 X-Originating-IP: [70.58.207.205] X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: ca64f275-b731-4c66-2061-08d7cc69ad3e X-MS-TrafficTypeDiagnostic: PU1PR01MB1882:|PU1PR01MB1882:|PU1PR01MB1882:|PU1PR01MB1882: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-LD-Processed: 0694623c-6669-497c-89c3-3a32a9934313,ExtAddr X-MS-Oob-TLC-OOBClassifiers: OLM:288; X-Forefront-PRVS: 03484C0ABF X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(396003)(346002)(366004)(376002)(136003)(39850400004)(199004)(6512007)(66476007)(30864003)(66556008)(6916009)(66946007)(6666004)(6486002)(508600001)(2616005)(4326008)(956004)(316002)(186003)(8676002)(16526019)(81166006)(6506007)(2906002)(5660300002)(52116002)(54906003)(26005)(44832011)(86362001)(36756003)(81156014)(8936002); DIR:OUT; SFP:1101; SCL:1; SRVR:PU1PR01MB1882; H:PU1PR01MB1964.apcprd01.prod.exchangelabs.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:0; Received-SPF: None (protection.outlook.com: cortina-access.com does not designate permitted sender hosts) X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: v91rd+/4I8ooGHO72QABVb2lMzaKFlY347VD6i+TWlDLQ8eJp2l0gd0NIBW38OhcnlgjXHMIiKd/z7loHdd4dykAqD+uYUPQSl08KQvG3Ty1Nb3s0HdE6xhulYtd85rqDOYWkibOX6g781+YVrDw0ZFnBMz3dSmp7O30AFtaOq5o2eh/a14vo0sYd/toeAKUwdnRg11wbtUlhuEQMxrhzQgO71wSBd+oUyZ7Ua3MzdwTDPYKLowYoFAsWO17jRTk6nhkcC+lIf1fxM064tTs6PxnPP6g2QocmdxDtTOwgD5t7EK1E2biVMVJYfNU5iEbmopC9KBYZyErxL5+msWqF+/MjQjneqsKrk33LOj+M8/cH7vn7beMr5R8CzYyfLa+Wa1Q76JFwIW32B9gSL3PX5MlOBcgS8kcuDnR9C4OjtJBUzaNR1oo0kSWKAcQgt57HClWFq1avYxoZB+AsRLqlsbXOSypyfGzhibFyz3XcRskjIrYPhlWZ4AcX9CKBDtPaAp/j8CtvDkbm9yFDUV9Rg== X-MS-Exchange-AntiSpam-MessageData: M3Wbe4i/3O18EtcE+SjMxBx2cqWewwt6R0kw3Jq303EdhOxVeeZrIKf6I/8PPoU2RsXiD3OpXzFiOUWBWpn/heB2SFzxq1Rv0NPGI78c8RdBlj/nv466yYqrSCRDzSEVxcKI+trlY49rT6b791F6Kw== X-OriginatorOrg: CORTINA-ACCESS.COM X-MS-Exchange-CrossTenant-Network-Message-Id: ca64f275-b731-4c66-2061-08d7cc69ad3e X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Mar 2020 00:57:35.0884 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 0694623c-6669-497c-89c3-3a32a9934313 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: OTgIP+6bY/U/ILe5TuVUs+6BPdcOcxTWpI2Un7gNGiy/g+3EJ4KHby2JEIS7pl5iWempuRF6gTnT32avQLtR5wP60qjUj6tClnhKo2kpH1slqTskojrP1a4E8GXxwqCb X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU1PR01MB1882 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.30rc1 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.2 at phobos.denx.de X-Virus-Status: Clean From: Arthur Li Add I2C controller support for Cortina Access CAxxxx SoCs Signed-off-by: Arthur Li Signed-off-by: Alex Nemirovsky CC: Heiko Schocher --- Changes in v3: None Changes in v2: None MAINTAINERS | 4 + drivers/i2c/Kconfig | 7 + drivers/i2c/Makefile | 1 + drivers/i2c/i2c-cortina.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/i2c/i2c-cortina.h | 92 ++++++++++++ 5 files changed, 450 insertions(+) create mode 100644 drivers/i2c/i2c-cortina.c create mode 100644 drivers/i2c/i2c-cortina.h diff --git a/MAINTAINERS b/MAINTAINERS index bb45d3c..b147faa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -181,6 +181,8 @@ F: drivers/gpio/cortina_gpio.c F: drivers/watchdog/cortina_wdt.c F: drivers/serial/serial_cortina.c F: drivers/mmc/ca_dw_mmc.c +F: drivers/i2c/i2c-cortina.c +F: drivers/i2c/i2c-cortina.h ARM/CZ.NIC TURRIS MOX SUPPORT M: Marek Behun @@ -672,6 +674,8 @@ F: drivers/gpio/cortina_gpio.c F: drivers/watchdog/cortina_wdt.c F: drivers/serial/serial_cortina.c F: drivers/mmc/ca_dw_mmc.c +F: drivers/i2c/i2c-cortina.c +F: drivers/i2c/i2c-cortina.h MIPS MSCC M: Gregory CLEMENT diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 03d2fed..b98a4aa 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -85,6 +85,13 @@ config SYS_I2C_CADENCE Say yes here to select Cadence I2C Host Controller. This controller is e.g. used by Xilinx Zynq. +config SYS_I2C_CA + tristate "Cortina-Access I2C Controller" + depends on DM_I2C && CORTINA_PLATFORM + default n + help + Say yes here to select Cortina-Access I2C Host Controller. + config SYS_I2C_DAVINCI bool "Davinci I2C Controller" depends on (ARCH_KEYSTONE || ARCH_DAVINCI) diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index f5a471f..5d18cf7 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o +obj-$(CONFIG_SYS_I2C_CA) += i2c-cortina.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o ifdef CONFIG_DM_PCI diff --git a/drivers/i2c/i2c-cortina.c b/drivers/i2c/i2c-cortina.c new file mode 100644 index 0000000..99c63f3 --- /dev/null +++ b/drivers/i2c/i2c-cortina.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2020 + * Arthur Li, Cortina Access, arthur.li@cortina-access.com. + */ + +#include +#include +#include +#include +#include +#include "i2c-cortina.h" + +static void set_speed(struct i2c_regs *regs, int i2c_spd) +{ + union ca_biw_cfg i2c_cfg; + + i2c_cfg.wrd = readl(®s->i2c_cfg); + i2c_cfg.bf.core_en = 0; + writel(i2c_cfg.wrd, ®s->i2c_cfg); + + switch (i2c_spd) { + case IC_SPEED_MODE_MAX: + i2c_cfg.bf.prer = + CORTINA_PER_IO_FREQ / (5 * I2C_MAX_SPEED) - 1; + break; + + case IC_SPEED_MODE_STANDARD: + i2c_cfg.bf.prer = + CORTINA_PER_IO_FREQ / (5 * I2C_STANDARD_SPEED) - 1; + break; + + case IC_SPEED_MODE_FAST: + default: + i2c_cfg.bf.prer = + CORTINA_PER_IO_FREQ / (5 * I2C_FAST_SPEED) - 1; + break; + } + + i2c_cfg.bf.core_en = 1; + writel(i2c_cfg.wrd, ®s->i2c_cfg); +} + +static int ca_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct ca_i2c *priv = dev_get_priv(bus); + int i2c_spd; + + if (speed >= I2C_MAX_SPEED) { + i2c_spd = IC_SPEED_MODE_MAX; + priv->speed = I2C_MAX_SPEED; + } else if (speed >= I2C_FAST_SPEED) { + i2c_spd = IC_SPEED_MODE_FAST; + priv->speed = I2C_FAST_SPEED; + } else { + i2c_spd = IC_SPEED_MODE_STANDARD; + priv->speed = I2C_STANDARD_SPEED; + } + + set_speed(priv->regs, i2c_spd); + + return 0; +} + +static int ca_i2c_get_bus_speed(struct udevice *bus) +{ + struct ca_i2c *priv = dev_get_priv(bus); + + return priv->speed; +} + +static void ca_i2c_init(struct i2c_regs *regs) +{ + union ca_biw_cfg i2c_cfg; + + i2c_cfg.wrd = readl(®s->i2c_cfg); + i2c_cfg.bf.core_en = 0; + i2c_cfg.bf.biw_soft_reset = 1; + writel(i2c_cfg.wrd, ®s->i2c_cfg); + mdelay(10); + i2c_cfg.bf.biw_soft_reset = 0; + writel(i2c_cfg.wrd, ®s->i2c_cfg); + + set_speed(regs, IC_SPEED_MODE_STANDARD); + + i2c_cfg.wrd = readl(®s->i2c_cfg); + i2c_cfg.bf.core_en = 1; + writel(i2c_cfg.wrd, ®s->i2c_cfg); +} + +static int i2c_wait_complete(struct i2c_regs *regs) +{ + union ca_biw_ctrl i2c_ctrl; + unsigned long start_time_bb = get_timer(0); + + i2c_ctrl.wrd = readl(®s->i2c_ctrl); + + while (i2c_ctrl.bf.biwdone == 0) { + i2c_ctrl.wrd = readl(®s->i2c_ctrl); + + if (get_timer(start_time_bb) > + (unsigned long)(I2C_BYTE_TO_BB)) { + printf("%s not done!!!\n", __func__); + return 1; + } + } + + /* Clear done bit */ + writel(i2c_ctrl.wrd, ®s->i2c_ctrl); + + return 0; +} + +static void i2c_setaddress(struct i2c_regs *regs, unsigned int i2c_addr, + int write_read) +{ + writel(i2c_addr | write_read, ®s->i2c_txr); + + writel(BIW_CTRL_START | BIW_CTRL_WRITE, + ®s->i2c_ctrl); + + i2c_wait_complete(regs); +} + +static int i2c_wait_for_bus_busy(struct i2c_regs *regs) +{ + union ca_biw_ack i2c_ack; + unsigned long start_time_bb = get_timer(0); + + i2c_ack.wrd = readl(®s->i2c_ack); + + while (i2c_ack.bf.biw_busy) { + i2c_ack.wrd = readl(®s->i2c_ack); + + if (get_timer(start_time_bb) > + (unsigned long)(I2C_BYTE_TO_BB)) { + printf("%s: timeout!\n", __func__); + return 1; + } + } + + return 0; +} + +static int i2c_xfer_init(struct i2c_regs *regs, uint8_t chip, uint addr, + int alen, int write_read) +{ + int addr_len = alen; + + if (i2c_wait_for_bus_busy(regs)) + return 1; + /* First cycle must write addr + offset */ + chip = ((chip & 0x7F) << 1); + if (alen == 0 && write_read == I2C_CMD_RD) + i2c_setaddress(regs, chip, I2C_CMD_RD); + else + i2c_setaddress(regs, chip, I2C_CMD_WT); + + while (alen) { + alen--; + writel(addr, ®s->i2c_txr); + if (write_read == I2C_CMD_RD) + writel(BIW_CTRL_WRITE | BIW_CTRL_STOP, + ®s->i2c_ctrl); + else + writel(BIW_CTRL_WRITE, ®s->i2c_ctrl); + i2c_wait_complete(regs); + } + + /* Send address again with Read flag if it's read command */ + if (write_read == I2C_CMD_RD && addr_len > 0) + i2c_setaddress(regs, chip, I2C_CMD_RD); + + return 0; +} + +static int i2c_xfer_finish(struct i2c_regs *regs) +{ + /* Dummy read makes bus free */ + writel(BIW_CTRL_READ | BIW_CTRL_STOP, ®s->i2c_ctrl); + i2c_wait_complete(regs); + + if (i2c_wait_for_bus_busy(regs)) { + printf("Timed out waiting for bus\n"); + return 1; + } + + return 0; +} + +static int ca_i2c_read(struct i2c_regs *regs, uint8_t chip, uint addr, + int alen, uint8_t *buffer, int len) +{ + unsigned long start_time_rx; + int rc = 0; + + if (i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_RD)) + return 1; + + start_time_rx = get_timer(0); + while (len) { + /* ACK_IN is ack value to send during read. + * ack high only on the very last byte! + */ + if (len == 1) { + writel(BIW_CTRL_READ | BIW_CTRL_ACK_IN | BIW_CTRL_STOP, + ®s->i2c_ctrl); + } else { + writel(BIW_CTRL_READ, ®s->i2c_ctrl); + } + + rc = i2c_wait_complete(regs); + udelay(1); + + if (rc == 0) { + *buffer++ = + (uchar) readl(®s->i2c_rxr); + len--; + start_time_rx = get_timer(0); + + } else if (get_timer(start_time_rx) > I2C_BYTE_TO) { + return 1; + } + } + i2c_xfer_finish(regs); + return rc; +} + +static int ca_i2c_write(struct i2c_regs *regs, uint8_t chip, uint addr, + int alen, uint8_t *buffer, int len) +{ + int rc, nb = len; + unsigned long start_time_tx; + + if (i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_WT)) + return 1; + + start_time_tx = get_timer(0); + while (len) { + writel(*buffer, ®s->i2c_txr); + if (len == 1) { + writel(BIW_CTRL_WRITE | BIW_CTRL_STOP, + ®s->i2c_ctrl); + } else { + writel(BIW_CTRL_WRITE, ®s->i2c_ctrl); + } + + rc = i2c_wait_complete(regs); + + if (rc == 0) { + len--; + buffer++; + start_time_tx = get_timer(0); + } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { + printf("Timed out. i2c write Failed\n"); + return 1; + } + } + + return 0; +} + +static int ca_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) +{ + struct ca_i2c *priv = dev_get_priv(bus); + int ret; + u32 tmp; + + /* Try to read the first location of the chip */ + ret = ca_i2c_read(priv->regs, chip_addr, 0, 1, (uchar *)&tmp, 1); + if (ret) + ca_i2c_init(priv->regs); + + return ret; +} + +static int ca_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) +{ + struct ca_i2c *priv = dev_get_priv(bus); + int ret; + + debug("i2c_xfer: %d messages\n", nmsgs); + for (; nmsgs > 0; nmsgs--, msg++) { + debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); + if (msg->flags & I2C_M_RD) { + ret = ca_i2c_read(priv->regs, msg->addr, 0, 0, + msg->buf, msg->len); + } else { + ret = ca_i2c_write(priv->regs, msg->addr, 0, 0, + msg->buf, msg->len); + } + + if (ret) { + debug("i2c_write: error sending\n"); + return -EREMOTEIO; + } + } + + return 0; +} + +static const struct dm_i2c_ops ca_i2c_ops = { + .xfer = ca_i2c_xfer, + .probe_chip = ca_i2c_probe_chip, + .set_bus_speed = ca_i2c_set_bus_speed, + .get_bus_speed = ca_i2c_get_bus_speed, +}; + +static const struct udevice_id ca_i2c_ids[] = { + { .compatible = "cortina,ca-i2c", }, + { } +}; + +static int ca_i2c_probe(struct udevice *bus) +{ + struct ca_i2c *priv = dev_get_priv(bus); + + ca_i2c_init(priv->regs); + + return 0; +} + +static int ca_i2c_ofdata_to_platdata(struct udevice *bus) +{ + struct ca_i2c *priv = dev_get_priv(bus); + + priv->regs = map_sysmem(dev_read_addr(bus), sizeof(struct i2c_regs)); + if (!priv->regs) { + printf("I2C: base address is invalid\n"); + return -EINVAL; + } + + return 0; +} + +U_BOOT_DRIVER(i2c_cortina) = { + .name = "i2c_cortina", + .id = UCLASS_I2C, + .of_match = ca_i2c_ids, + .ofdata_to_platdata = ca_i2c_ofdata_to_platdata, + .probe = ca_i2c_probe, + .priv_auto_alloc_size = sizeof(struct ca_i2c), + .ops = &ca_i2c_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/i2c/i2c-cortina.h b/drivers/i2c/i2c-cortina.h new file mode 100644 index 0000000..f1c3dc7 --- /dev/null +++ b/drivers/i2c/i2c-cortina.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 + * Cortina Access, + */ + +#ifndef __CA_I2C_H_ +#define __CA_I2C_H_ + +#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__) +struct i2c_regs { + u32 i2c_cfg; + u32 i2c_ctrl; + u32 i2c_txr; + u32 i2c_rxr; + u32 i2c_ack; + u32 i2c_ie0; + u32 i2c_int0; + u32 i2c_ie1; + u32 i2c_int1; + u32 i2c_stat; +}; + +union ca_biw_cfg { + struct biw_cfg { + u32 core_en : 1; + u32 biw_soft_reset : 1; + u32 busywait_en : 1; + u32 stretch_en : 1; + u32 arb_en : 1; + u32 clksync_en : 1; + u32 rsrvd1 : 2; + u32 spike_cnt : 4; + u32 rsrvd2 : 4; + u32 prer : 16; + } bf; + unsigned int wrd; +}; + +union ca_biw_ctrl { + struct biw_ctrl { + u32 biwdone : 1; + u32 rsrvd1 : 2; + u32 ack_in : 1; + u32 write : 1; + u32 read : 1; + u32 stop : 1; + u32 start : 1; + u32 rsrvd2 : 24; + } bf; + unsigned int wrd; +}; + +union ca_biw_ack { + struct biw_ack { + u32 al :1; + u32 biw_busy :1; + u32 ack_out :1; + u32 rsrvd1 :29; + } bf; + unsigned int wrd; +}; +#endif /* !__ASSEMBLER__*/ + +struct ca_i2c { + struct i2c_regs *regs; + unsigned int speed; +}; + +#define I2C_CMD_WT 0 +#define I2C_CMD_RD 1 + +#define BIW_CTRL_DONE BIT(0) +#define BIW_CTRL_ACK_IN BIT(3) +#define BIW_CTRL_WRITE BIT(4) +#define BIW_CTRL_READ BIT(5) +#define BIW_CTRL_STOP BIT(6) +#define BIW_CTRL_START BIT(7) + +#define I2C_BYTE_TO (CONFIG_SYS_HZ / 500) +#define I2C_STOPDET_TO (CONFIG_SYS_HZ / 500) +#define I2C_BYTE_TO_BB (10) + +#define IC_SPEED_MODE_STANDARD 1 +#define IC_SPEED_MODE_FAST 2 +#define IC_SPEED_MODE_MAX 3 + +#define I2C_MAX_SPEED 1000000 +#define I2C_FAST_SPEED 400000 +#define I2C_STANDARD_SPEED 100000 + +#endif /* __CA_I2C_H_ */