From patchwork Wed Aug 7 00:36:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jeffery X-Patchwork-Id: 1143090 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 463CKN2xp8z9s7T for ; Wed, 7 Aug 2019 10:38:16 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=aj.id.au Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=aj.id.au header.i=@aj.id.au header.b="gO0q/4nZ"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="vq9r47Rt"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 463CKN17QmzDqvw for ; Wed, 7 Aug 2019 10:38:16 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Delivered-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=aj.id.au (client-ip=66.111.4.221; helo=new1-smtp.messagingengine.com; envelope-from=andrew@aj.id.au; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=aj.id.au Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=aj.id.au header.i=@aj.id.au header.b="gO0q/4nZ"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="vq9r47Rt"; dkim-atps=neutral Received: from new1-smtp.messagingengine.com (new1-smtp.messagingengine.com [66.111.4.221]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 463CK861QMzDqpG for ; Wed, 7 Aug 2019 10:38:04 +1000 (AEST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id 6764927D4; Tue, 6 Aug 2019 20:38:02 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 06 Aug 2019 20:38:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aj.id.au; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm3; bh=rqpiLLusQurvK WQs9c8c91zRlnYataWeo+My6eoeOzA=; b=gO0q/4nZt1GsBCEkq5ReozR8M7+0c 1zt/Z2Z4aPpn2jij+lNkIfFewCU+831zc1VwJVQEN/fGM5VzYTXV8nED/tgFB9FL 1sx/F8pt8I+FH/+AhQW+jEgyUpBjR39vDLLkxPTWWQ7/Rwt3hI3ZsvR84LuFKgKl 8TZzWXy9Q1MrjJDqYf6EDWSEs7MzqOOf4j2o7YlgysugUeA2EhoaIsZ8gvxjbFC+ vMIG/RJWh9mhnNriFpH3mATQmWerlc1c1YvPaC/MLZQdzpnFlHFab9JiI5I6aylc 0AcyegN+jDnlpWirEsUkF7UvwV18u1hrcunvuQZxuTp8ThehtuoXq18/A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=rqpiLLusQurvKWQs9c8c91zRlnYataWeo+My6eoeOzA=; b=vq9r47Rt VjPznrxmuvGPnSX1kaqMzmdVWRBBSRaNOfv4a3kyqfusk8DmilaLPHkbpl4FdC1k NZj/4WN/byJPDaScGDIxLdUys/8MCKYi4njH1dfXVNnv2BZ0nDbLzDgjSZiEo4cg AIivX/6raykk0gmuYvukVp92VdKs1mTqVs83liU1esW+xgPSwq9TGip/ajcyeRF2 /2ddOqKzBJXyqqbyv2+7HN1IC6tL8p5zA9zu8Dq3R+bh/ifSrjyjn/tw0WeDwcmk VK083PZYzkXIWf+0bGrt9e+lhBcT491mYr7FJbudlazcZQ1eyVo+ldNeFyEb7X/j 9rn258/oG9xKig== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduvddrudduuddgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefhvffufffkofgjfhgggfestdekre dtredttdenucfhrhhomheptehnughrvgifucflvghffhgvrhihuceorghnughrvgifsegr jhdrihgurdgruheqnecuffhomhgrihhnpeguvghvihgtvghtrhgvvgdrohhrghenucfkph epvddtvddrkedurddukedrfedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrnhgurhgv fiesrghjrdhiugdrrghunecuvehluhhsthgvrhfuihiivgeptd X-ME-Proxy: Received: from mistburn.au.ibm.com (bh02i525f01.au.ibm.com [202.81.18.30]) by mail.messagingengine.com (Postfix) with ESMTPA id 50003380088; Tue, 6 Aug 2019 20:37:58 -0400 (EDT) From: Andrew Jeffery To: linux-mmc@vger.kernel.org Subject: [PATCH v5 1/2] dt-bindings: mmc: Document Aspeed SD controller Date: Wed, 7 Aug 2019 10:06:28 +0930 Message-Id: <20190807003629.2974-2-andrew@aj.id.au> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190807003629.2974-1-andrew@aj.id.au> References: <20190807003629.2974-1-andrew@aj.id.au> MIME-Version: 1.0 X-BeenThere: linux-aspeed@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux ASPEED SoC development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, ulf.hansson@linaro.org, linux-aspeed@lists.ozlabs.org, ryanchen.aspeed@gmail.com, adrian.hunter@intel.com, linux-kernel@vger.kernel.org, robh+dt@kernel.org, linux-arm-kernel@lists.infradead.org Errors-To: linux-aspeed-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Linux-aspeed" The ASPEED SD/SDIO/MMC controller exposes two slots implementing the SDIO Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if only a single slot is enabled. Signed-off-by: Andrew Jeffery Reviewed-by: Rob Herring Reviewed-by: Joel Stanley --- v4: * Make use of mmc-controller.yaml * Document sdhci,auto-cmd12 v2: * Fix compatible enums * Add AST2600 compatibles * Describe #address-cells / #size-cells --- .../devicetree/bindings/mmc/aspeed,sdhci.yaml | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml new file mode 100644 index 000000000000..570f8c72662b --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/aspeed,sdhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASPEED SD/SDIO/MMC Controller + +maintainers: + - Andrew Jeffery + - Ryan Chen + +description: |+ + The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the SDIO + Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if + only a single slot is enabled. + + The two slots are supported by a common configuration area. As the SDHCIs for + the slots are dependent on the common configuration area, they are described + as child nodes. + +properties: + compatible: + enum: + - aspeed,ast2400-sd-controller + - aspeed,ast2500-sd-controller + - aspeed,ast2600-sd-controller + reg: + maxItems: 1 + description: Common configuration registers + "#address-cells": + const: 1 + "#size-cells": + const: 1 + ranges: true + clocks: + maxItems: 1 + description: The SD/SDIO controller clock gate + +patternProperties: + "^sdhci@[0-9a-f]+$": + type: object + allOf: + - $ref: mmc-controller.yaml + properties: + compatible: + enum: + - aspeed,ast2400-sdhci + - aspeed,ast2500-sdhci + - aspeed,ast2600-sdhci + reg: + maxItems: 1 + description: The SDHCI registers + clocks: + maxItems: 1 + description: The SD bus clock + interrupts: + maxItems: 1 + description: The SD interrupt shared between both slots + sdhci,auto-cmd12: + type: boolean + description: Specifies that controller should use auto CMD12 + required: + - compatible + - reg + - clocks + - interrupts + +additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - ranges + - clocks + +examples: + - | + #include + sdc@1e740000 { + compatible = "aspeed,ast2500-sd-controller"; + reg = <0x1e740000 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1e740000 0x10000>; + clocks = <&syscon ASPEED_CLK_GATE_SDCLK>; + + sdhci0: sdhci@100 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x100 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + }; + + sdhci1: sdhci@200 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x200 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + }; + }; From patchwork Wed Aug 7 00:36:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jeffery X-Patchwork-Id: 1143091 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 463CKT47z4z9s7T for ; Wed, 7 Aug 2019 10:38:21 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=aj.id.au Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=aj.id.au header.i=@aj.id.au header.b="lq3qZoil"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="nMvXkW+a"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 463CKT34cmzDqyn for ; Wed, 7 Aug 2019 10:38:21 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Delivered-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=aj.id.au (client-ip=66.111.4.221; helo=new1-smtp.messagingengine.com; envelope-from=andrew@aj.id.au; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=aj.id.au Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=aj.id.au header.i=@aj.id.au header.b="lq3qZoil"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="nMvXkW+a"; dkim-atps=neutral Received: from new1-smtp.messagingengine.com (new1-smtp.messagingengine.com [66.111.4.221]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 463CKF1z6PzDqvd for ; Wed, 7 Aug 2019 10:38:09 +1000 (AEST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id E0B2F27D7; Tue, 6 Aug 2019 20:38:06 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 06 Aug 2019 20:38:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aj.id.au; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm3; bh=0AhfLkPhnd4xC wAQK+J4LZ4tY5K4fs7DvSdi94mwKvI=; b=lq3qZoilyXTaJIGwUihhB5rPeRlpk 2SU4LTn//Gah2WBfO1mgeKgoOG54UkdAiO5LDOb35KIvGJlDl8ur8fTBLEGMca8z jkxAHb5EOI03OrpG+AXuRpBnAo1Di23DJh7RWST/eW5QbpqOGdmjUkeZ/VJ4izd9 GaeX3kRVDWCYmVwB2xniee1A1vNrbf570MzxWGcnOJH9fZ1IjqmWyFMZOm5ygvRR htA5NwleKFsVwIjdQ2YDiNSIh+bH5RJd5mgHq8CZIcu2hZ8f0EqRyhap+1yywvQ8 F9PjEq1pk4LRsbvgUtVIqzwy0LV7/EZCwgOAapWpB54TAiSEeLwx7zYNQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=0AhfLkPhnd4xCwAQK+J4LZ4tY5K4fs7DvSdi94mwKvI=; b=nMvXkW+a tVR1nh8jQRgOAZVrBVjWtyuxWyiVepuNRVRa/gOHMLujZIn4GjlrMnRby78Bwyri u7uXM37oqYekV4dqDnhSXTWFSVeRnDDbXc1S+dD6oF3Y7FHwmTYobvnPVAkIRbTl PLmrijfH8ZTXTh4mSo1Oq6Q6M9uAvov5V+DmI6DGEdyzYr6oaT2QqwrA8WaPm0TK Jg5J71japt4zzF9iJQXNRRv27nWOdp4M5Msw3GetiIStLtYmorZEy/7E+hdfhigI FDyTbRiqVqtOg1AOyu6q37N32/qdUQ+NITqVDnIoSYVtnBVxwX7HlTMv1eqMi7sN +gMmksQP+e96jQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduvddrudduuddgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefhvffufffkofgjfhgggfestdekre dtredttdenucfhrhhomheptehnughrvgifucflvghffhgvrhihuceorghnughrvgifsegr jhdrihgurdgruheqnecukfhppedvtddvrdekuddrudekrdeftdenucfrrghrrghmpehmrg hilhhfrhhomheprghnughrvgifsegrjhdrihgurdgruhenucevlhhushhtvghrufhiiigv pedt X-ME-Proxy: Received: from mistburn.au.ibm.com (bh02i525f01.au.ibm.com [202.81.18.30]) by mail.messagingengine.com (Postfix) with ESMTPA id 84135380086; Tue, 6 Aug 2019 20:38:02 -0400 (EDT) From: Andrew Jeffery To: linux-mmc@vger.kernel.org Subject: [PATCH v5 2/2] mmc: Add support for the ASPEED SD controller Date: Wed, 7 Aug 2019 10:06:29 +0930 Message-Id: <20190807003629.2974-3-andrew@aj.id.au> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190807003629.2974-1-andrew@aj.id.au> References: <20190807003629.2974-1-andrew@aj.id.au> MIME-Version: 1.0 X-BeenThere: linux-aspeed@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux ASPEED SoC development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, ulf.hansson@linaro.org, linux-aspeed@lists.ozlabs.org, ryanchen.aspeed@gmail.com, adrian.hunter@intel.com, linux-kernel@vger.kernel.org, robh+dt@kernel.org, linux-arm-kernel@lists.infradead.org Errors-To: linux-aspeed-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Linux-aspeed" Add a minimal driver for ASPEED's SD controller, which exposes two SDHCIs. The ASPEED design implements a common register set for the SDHCIs, and moves some of the standard configuration elements out to this common area (e.g. 8-bit mode, and card detect configuration which is not currently supported). The SD controller has a dedicated hardware interrupt that is shared between the slots. The common register set exposes information on which slot triggered the interrupt; early revisions of the patch introduced an irqchip for the register, but reality is it doesn't behave as an irqchip, and the result fits awkwardly into the irqchip APIs. Instead I've taken the simple approach of using the IRQ as a shared IRQ with some minor performance impact for the second slot. Ryan was the original author of the patch - I've taken his work and massaged it to drop the irqchip support and rework the devicetree integration. The driver has been smoke tested under qemu against a minimal SD controller model and lightly tested on an ast2500-evb. Signed-off-by: Ryan Chen Signed-off-by: Andrew Jeffery Acked-by: Adrian Hunter Reviewed-by: Joel Stanley --- v5: * Cleanup sdhci driver on registration failure v4: No change v2: * Add AST2600 compatible * Drop SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN * Ensure slot number is valid * Fix build with CONFIG_MODULES * Fix module license string * Non-PCI devices won't die * Rename aspeed_sdc_configure_8bit_mode() * Rename aspeed_sdhci_pdata * Switch to sdhci_enable_clk() * Use PTR_ERR() on the right `struct platform_device *` --- drivers/mmc/host/Kconfig | 12 ++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-of-aspeed.c | 332 +++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 14d89a108edd..0f8a230de2f3 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -154,6 +154,18 @@ config MMC_SDHCI_OF_ARASAN If unsure, say N. +config MMC_SDHCI_OF_ASPEED + tristate "SDHCI OF support for the ASPEED SDHCI controller" + depends on MMC_SDHCI_PLTFM + depends on OF + help + This selects the ASPEED Secure Digital Host Controller Interface. + + If you have a controller with this interface, say Y or M here. You + also need to enable an appropriate bus interface. + + If unsure, say N. + config MMC_SDHCI_OF_AT91 tristate "SDHCI OF support for the Atmel SDMMC controller" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 73578718f119..390ee162fe71 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o +obj-$(CONFIG_MMC_SDHCI_OF_ASPEED) += sdhci-of-aspeed.o obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c new file mode 100644 index 000000000000..8bb095ca2fa9 --- /dev/null +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (C) 2019 ASPEED Technology Inc. */ +/* Copyright (C) 2019 IBM Corp. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +#define ASPEED_SDC_INFO 0x00 +#define ASPEED_SDC_S1MMC8 BIT(25) +#define ASPEED_SDC_S0MMC8 BIT(24) + +struct aspeed_sdc { + struct clk *clk; + struct resource *res; + + spinlock_t lock; + void __iomem *regs; +}; + +struct aspeed_sdhci { + struct aspeed_sdc *parent; + u32 width_mask; +}; + +static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc *sdc, + struct aspeed_sdhci *sdhci, + bool bus8) +{ + u32 info; + + /* Set/clear 8 bit mode */ + spin_lock(&sdc->lock); + info = readl(sdc->regs + ASPEED_SDC_INFO); + if (bus8) + info |= sdhci->width_mask; + else + info &= ~sdhci->width_mask; + writel(info, sdc->regs + ASPEED_SDC_INFO); + spin_unlock(&sdc->lock); +} + +static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + int div; + u16 clk; + + if (clock == host->clock) + return; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + goto out; + + for (div = 1; div < 256; div *= 2) { + if ((host->max_clk / div) <= clock) + break; + } + div >>= 1; + + clk = div << SDHCI_DIVIDER_SHIFT; + + sdhci_enable_clk(host, clk); + +out: + host->clock = clock; +} + +static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width) +{ + struct sdhci_pltfm_host *pltfm_priv; + struct aspeed_sdhci *aspeed_sdhci; + struct aspeed_sdc *aspeed_sdc; + u8 ctrl; + + pltfm_priv = sdhci_priv(host); + aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv); + aspeed_sdc = aspeed_sdhci->parent; + + /* Set/clear 8-bit mode */ + aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci, + width == MMC_BUS_WIDTH_8); + + /* Set/clear 1 or 4 bit mode */ + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + if (width == MMC_BUS_WIDTH_4) + ctrl |= SDHCI_CTRL_4BITBUS; + else + ctrl &= ~SDHCI_CTRL_4BITBUS; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +} + +static const struct sdhci_ops aspeed_sdhci_ops = { + .set_clock = aspeed_sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = aspeed_sdhci_set_bus_width, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data aspeed_sdhci_pdata = { + .ops = &aspeed_sdhci_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +}; + +static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev, + struct resource *res) +{ + resource_size_t delta; + + if (!res || resource_type(res) != IORESOURCE_MEM) + return -EINVAL; + + if (res->start < dev->parent->res->start) + return -EINVAL; + + delta = res->start - dev->parent->res->start; + if (delta & (0x100 - 1)) + return -EINVAL; + + return (delta / 0x100) - 1; +} + +static int aspeed_sdhci_probe(struct platform_device *pdev) +{ + struct sdhci_pltfm_host *pltfm_host; + struct aspeed_sdhci *dev; + struct sdhci_host *host; + struct resource *res; + int slot; + int ret; + + host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev)); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + dev = sdhci_pltfm_priv(pltfm_host); + dev->parent = dev_get_drvdata(pdev->dev.parent); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + slot = aspeed_sdhci_calculate_slot(dev, res); + + if (slot < 0) + return slot; + else if (slot >= 2) + return -EINVAL; + + dev_info(&pdev->dev, "Configuring for slot %d\n", slot); + dev->width_mask = !slot ? ASPEED_SDC_S0MMC8 : ASPEED_SDC_S1MMC8; + + sdhci_get_of_property(pdev); + + pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pltfm_host->clk)) + return PTR_ERR(pltfm_host->clk); + + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable SDIO clock\n"); + goto err_pltfm_free; + } + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_sdhci_add; + + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci_add; + + return 0; + +err_sdhci_add: + clk_disable_unprepare(pltfm_host->clk); +err_pltfm_free: + sdhci_pltfm_free(pdev); + return ret; +} + +static int aspeed_sdhci_remove(struct platform_device *pdev) +{ + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_host *host; + int dead = 0; + + host = platform_get_drvdata(pdev); + pltfm_host = sdhci_priv(host); + + sdhci_remove_host(host, dead); + + clk_disable_unprepare(pltfm_host->clk); + + sdhci_pltfm_free(pdev); + + return 0; +} + +static const struct of_device_id aspeed_sdhci_of_match[] = { + { .compatible = "aspeed,ast2400-sdhci", }, + { .compatible = "aspeed,ast2500-sdhci", }, + { .compatible = "aspeed,ast2600-sdhci", }, + { } +}; + +static struct platform_driver aspeed_sdhci_driver = { + .driver = { + .name = "sdhci-aspeed", + .of_match_table = aspeed_sdhci_of_match, + }, + .probe = aspeed_sdhci_probe, + .remove = aspeed_sdhci_remove, +}; + +static int aspeed_sdc_probe(struct platform_device *pdev) + +{ + struct device_node *parent, *child; + struct aspeed_sdc *sdc; + int ret; + + sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL); + if (!sdc) + return -ENOMEM; + + spin_lock_init(&sdc->lock); + + sdc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sdc->clk)) + return PTR_ERR(sdc->clk); + + ret = clk_prepare_enable(sdc->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable SDCLK\n"); + return ret; + } + + sdc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sdc->regs = devm_ioremap_resource(&pdev->dev, sdc->res); + if (IS_ERR(sdc->regs)) { + ret = PTR_ERR(sdc->regs); + goto err_clk; + } + + dev_set_drvdata(&pdev->dev, sdc); + + parent = pdev->dev.of_node; + for_each_available_child_of_node(parent, child) { + struct platform_device *cpdev; + + cpdev = of_platform_device_create(child, NULL, &pdev->dev); + if (IS_ERR(cpdev)) { + of_node_put(child); + ret = PTR_ERR(cpdev); + goto err_clk; + } + } + + return 0; + +err_clk: + clk_disable_unprepare(sdc->clk); + return ret; +} + +static int aspeed_sdc_remove(struct platform_device *pdev) +{ + struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev); + + clk_disable_unprepare(sdc->clk); + + return 0; +} + +static const struct of_device_id aspeed_sdc_of_match[] = { + { .compatible = "aspeed,ast2400-sd-controller", }, + { .compatible = "aspeed,ast2500-sd-controller", }, + { .compatible = "aspeed,ast2600-sd-controller", }, + { } +}; + +MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match); + +static struct platform_driver aspeed_sdc_driver = { + .driver = { + .name = "sd-controller-aspeed", + .pm = &sdhci_pltfm_pmops, + .of_match_table = aspeed_sdc_of_match, + }, + .probe = aspeed_sdc_probe, + .remove = aspeed_sdc_remove, +}; + +static int __init aspeed_sdc_init(void) +{ + int rc; + + rc = platform_driver_register(&aspeed_sdhci_driver); + if (rc < 0) + return rc; + + rc = platform_driver_register(&aspeed_sdc_driver); + if (rc < 0) + platform_driver_unregister(&aspeed_sdhci_driver); + + return rc; +} +module_init(aspeed_sdc_init); + +static void __exit aspeed_sdc_exit(void) +{ + platform_driver_unregister(&aspeed_sdc_driver); + platform_driver_unregister(&aspeed_sdhci_driver); +} +module_exit(aspeed_sdc_exit); + +MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers"); +MODULE_AUTHOR("Ryan Chen "); +MODULE_AUTHOR("Andrew Jeffery "); +MODULE_LICENSE("GPL");