From patchwork Thu Feb 27 07:58:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Nemirovsky X-Patchwork-Id: 1245628 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=lYEdy8E5; 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 48SlSj2hf0z9sPK for ; Thu, 27 Feb 2020 18:59:49 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 88451811F0; Thu, 27 Feb 2020 08:59:10 +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="lYEdy8E5"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 8C9428089D; Thu, 27 Feb 2020 08:58:47 +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-hk2apc01on061e.outbound.protection.outlook.com [IPv6:2a01:111:f400:febc::61e]) (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 2AE9B80829 for ; Thu, 27 Feb 2020 08:58:42 +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=S1D43iYYb6QOHNyL+fVrkswpZrnYbXvYaIfH6LXeyE4/Y/nEhyhhwjS3i/6h69+ZAZMBSRxOOA40bdw2VRvWF3x2j9wRfy8QHagJJxML3owQJfW+Tk1Pbj7Okxf0lOkLzhYM+elGuI7+K72V/Y/uFRA7ZFW/3Pc6TNcEuupTZGu5tLJ2OdIn80i/9CmUuZEZOO+flyPyFpKtaASckiSCVY5FVOHOXrR0BCcLKPj5FVp7Vv9HzSXzO+pDjxmwVG/cLRSbcvtfqPb+eRaZ+NX7ttzTAQxtLlL2pZJUjLmcoH1RXfhlUcP4yOiZfB09fYEP1SYimGTOsrQ7H9crJxT1xg== 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=vJ2aJhQwjyIJGttcONVkm2vV3NvH8wk0O2SToihyoLc=; b=it1Y2TzNph756VaNJdyukc8LBe1dcmbROPG4tTjeky7MOwn/5buLGrLtiX2DktoReR0DQA79Qh5qeUVu//O+knjz2PH1+oqNKBce/v7VmVogQS9nVjkUE7Mub301Xj1nI6tWnR6Rksf8UCRQYyDUBqTjBk3dWXOvcbrLfnpOwOQL2mKZipR58JKeXt04qRrgVprpLLJ4FmfH3wxuKYWpyPYgqkT6gyTIk07EZsClooESz1IbmyyPN29SxmN/NpI+X05F1HCXOJ20oUljt/x+rLHx3QfBxiXqH8EFlo9K1pmPNeSmUgoZ3677JxxF36vObpZJkSuR6hOI1BEgSQHyCQ== 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=vJ2aJhQwjyIJGttcONVkm2vV3NvH8wk0O2SToihyoLc=; b=lYEdy8E5Uwv37aZQVLY9rSzFBusDio3wFUmCXJowLfiaDGPFua5QHZ4ejV5G32MJzeCy/hD1UKKPjqt17IQ3YdldcsmyaUjCl4iDmAvuxjwMIJA0/VEbYnKOHTPkJaaRBUPemaW43srfewptHpX1SliUvU3WQJimWIN38UFjRIU= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Alex.Nemirovsky@cortina-access.com; Received: from TY2PR0101MB2445.apcprd01.prod.exchangelabs.com (20.177.47.144) by TY2PR0101MB2461.apcprd01.prod.exchangelabs.com (20.177.79.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2750.21; Thu, 27 Feb 2020 07:58:34 +0000 Received: from TY2PR0101MB2445.apcprd01.prod.exchangelabs.com ([fe80::7169:58ba:bc62:2231]) by TY2PR0101MB2445.apcprd01.prod.exchangelabs.com ([fe80::7169:58ba:bc62:2231%7]) with mapi id 15.20.2772.012; Thu, 27 Feb 2020 07:58:34 +0000 From: Alex Nemirovsky To: u-boot@lists.denx.de Cc: Arthur Li , Alex Nemirovsky Subject: [PATCH v2 3/8] i2c: i2c-cortina: added CAxxxx I2C support Date: Wed, 26 Feb 2020 23:58:13 -0800 Message-Id: <1582790298-5546-4-git-send-email-alex.nemirovsky@cortina-access.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1582790298-5546-1-git-send-email-alex.nemirovsky@cortina-access.com> References: <1582790298-5546-1-git-send-email-alex.nemirovsky@cortina-access.com> X-ClientProxiedBy: CO2PR04CA0177.namprd04.prod.outlook.com (2603:10b6:104:4::31) To TY2PR0101MB2445.apcprd01.prod.exchangelabs.com (2603:1096:404:68::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from smok.hrh.localdomain (70.58.207.205) by CO2PR04CA0177.namprd04.prod.outlook.com (2603:10b6:104:4::31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.20.2772.14 via Frontend Transport; Thu, 27 Feb 2020 07:58: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: caee0942-fb14-4c79-c16f-08d7bb5ad810 X-MS-TrafficTypeDiagnostic: TY2PR0101MB2461:|TY2PR0101MB2461:|TY2PR0101MB2461:|TY2PR0101MB2461: 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: 03264AEA72 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(39850400004)(366004)(136003)(376002)(346002)(396003)(199004)(189003)(2906002)(5660300002)(52116002)(86362001)(8936002)(8676002)(6666004)(4326008)(6916009)(81166006)(30864003)(36756003)(81156014)(54906003)(107886003)(186003)(66556008)(26005)(2616005)(44832011)(508600001)(956004)(6486002)(6512007)(6506007)(66946007)(16526019)(316002)(66476007); DIR:OUT; SFP:1101; SCL:1; SRVR:TY2PR0101MB2461; H:TY2PR0101MB2445.apcprd01.prod.exchangelabs.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:0; MX:1; 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: +1troDOlNAYXZ1RVqAR/YPAENfZ9AKUeWdw1gJ+eTjiHJBusN7CUlunRDYqVjmEW4peVAjg7KQuRByX5T/pp5LSo+VI6VlVwRfoKKeQGU7XMrB1yyBDSg8zvG7nWN+oX4URIEVOWTgzrOfAQEgnax46jxAjlA8OtlgghxUVeRaZoe5DffRMOY2JLVhpY/6E47Nsa0FwtT6RW06UG/I4fCtIigzoCK1K81R6VsqvAVeIAtPuXpQQcNk1fyuVLyjLT83ziOXeqeaCVNghYFy53OHa4j99I+C13cUty+yydTZjUtGMZFvvZIdYRnOtnNmn2AHiyg1VPn/pKLtuAm6fZp99gT0IRPdpX+HKs3PoR0ItrFeclJFM2Zj7NNaGbpHSZKT9XNnSyQ8483eX7cX4fYf+8xvuMqmqSiEuzG0bgKkOdrxjrOds78sX7iWUurVngS/HMoMupX5kVRKjTBHbnFs0DpJDRPM29X8xwnjho59PhwbYv/NQb9aWqikQjgm1gbxc7Bwtnr1TlbOZq//VUjg== X-MS-Exchange-AntiSpam-MessageData: 0fmSbTDnLME552Og8xvaa72oClLskqPleYeiQF8Cz5y1XMhT+J8FlD/XuUJyOdpTRvz/0Jj/8XEP0VvhH0DwM4y8Sr3uJWUxzK7eERnvos0ecRXXuN/yqFiplOwRY5K1+TSVpgJbdU1/klk4kGcK9A== X-OriginatorOrg: CORTINA-ACCESS.COM X-MS-Exchange-CrossTenant-Network-Message-Id: caee0942-fb14-4c79-c16f-08d7bb5ad810 X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Feb 2020 07:58:34.6579 (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: Z2I7KMoId5TZdcZmmTEFbtsG+lPYuUUSyecDu0jqiFeGwgC1ZnFnGSSxRSni9S2lZ8vIixGMj8B+hL9KulZvLG7y91aIYHSV2lsY33M2Pa+DkqyR7sgx9TvbVgh+Rd0y X-MS-Exchange-Transport-CrossTenantHeadersStamped: TY2PR0101MB2461 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 --- 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_ */