Received: by 2002:ac0:946b:0:0:0:0:0 with SMTP id j40csp2053367imj; Fri, 8 Feb 2019 11:45:05 -0800 (PST) X-Google-Smtp-Source: AHgI3IbOdu9E/khxgtB5ry7rekPwACL6F32LJkaSjb+nGH9mfMBOYDOuAqVJz2TPz55NcLcO/0mU X-Received: by 2002:a62:5658:: with SMTP id k85mr23695433pfb.231.1549655105216; Fri, 08 Feb 2019 11:45:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549655105; cv=none; d=google.com; s=arc-20160816; b=PjA9m2sCtRoFdx00uWFieoLm8JW7Z/cTf6y2+2EzJKlLjzY60dX5xJOhfFnIeYtAbX N1xWCRqXzmfph0qMDf3pPgKXCnDIUgcUwULpOX22agT8izN/h8+cz726uhu+LHc44Bl+ NPVm9vzBYIftExp3HEPGs4YDXFBre3ximREhNFAew3aDnvrbiTzeuef0u0BE5YMS+r4i o8MrK6d64ljR4kjlJ3bzZOFW0UhL3afbqSioB2ebVj3ynUsgXq9L9nV4w1XcYfnWBL+4 RXQ4GEFstEPFyhfZO9UUUk+uZnkVJflfK8PvBBABQ6xYb1QLtOS4qGymm2isWZK0o1Cw ErsQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=/T+rmaO0WsJ3fdj6MWlVJqdKPjzzcqK1ViXBonhWe6g=; b=KVXBwhwHT2plmZYIlzqYWW2hdEZdBrsS4lFYVFxiePh/00GPv13IDPxPOgQPKpn6NJ TuOElScuoLytdMYB1pQ5P5T+o38QI6QkWzdaj+/VmEbRcjRff0LYCnhLip2lMOxuMWPj QM/t+BCJOSqtKpkhvYmJMELpyLwNkVKdM7AfbRqeyhccpfksy3q6a+VbjyiqAGCly02G GGdOtVdRg+ZD5TZszG6A2XMhRUN79C9RB4/c+SHHYMLRebJcaieyggSTbwe+nWxppv8X MaQw3K51PrtPK0hvwQoxbrXVq35p5hLgrwUsMOu01rs0KAsVmGtcoHAEfCuMeABk/UoX h4Vw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Jt0ShRWD; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f95si3390512plb.60.2019.02.08.11.44.49; Fri, 08 Feb 2019 11:45:05 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Jt0ShRWD; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727974AbfBHTjE (ORCPT + 99 others); Fri, 8 Feb 2019 14:39:04 -0500 Received: from mail-it1-f194.google.com ([209.85.166.194]:40925 "EHLO mail-it1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727957AbfBHTjC (ORCPT ); Fri, 8 Feb 2019 14:39:02 -0500 Received: by mail-it1-f194.google.com with SMTP id h193so11787740ita.5 for ; Fri, 08 Feb 2019 11:39:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/T+rmaO0WsJ3fdj6MWlVJqdKPjzzcqK1ViXBonhWe6g=; b=Jt0ShRWDMRLY1L5+el2ZOmI8ZqoA1j0Yjafc+zPewgOD1VNF7caYnHwKQ4zV1yYJ6z fKjeM4WM+UkUEnrsf/j673R+NCh+A8Q6KMxCnJhV2KHG9x5Q5UVC93yXnr0ymhAXjz5t 3/LOLVEjMVr7akReXXAyWgQaZ+50oN/U649qc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/T+rmaO0WsJ3fdj6MWlVJqdKPjzzcqK1ViXBonhWe6g=; b=AFyRvbJZc+9xq/kuxaUuJIbdDrTngikLjfNyF6dE/eoh1nRGmZ9j7dS8fybKJAF6b7 cqykLBpCdrhT5IU5vBJ9XZLAAdFXKhHVfhsvuvMDIrQCHk8KwsvfwGUPlLqQ9sjb0caJ peQ+3/oBRNoEiHsXZfiA4Ye19yF3HmqDddAKB+frL0GI+U7beXIJQNskC9mJcHYFfH3W 7n7adEryL6aXYYKNauNr4tE0Hq62ZRzqhY85kekkFBWZs4GlbMDAP9iGI3HqPAgtw1Tg n/1PiY6qJjJoodxuMKecWTW+bSoHOrYz0o+i0zJiiKpHQ+d9cRee/e97Ch9gIO68lwd6 g4Kw== X-Gm-Message-State: AHQUAuZN+SoNHuJVH0THiGZUW+AVAKm+0ObewLHfJWB5phBxdZPbHs8s xv96VXLPRJgoEJQYl4M1DRGXSDaKzPE= X-Received: by 2002:a5d:9650:: with SMTP id d16mr1135073ios.289.1549654740745; Fri, 08 Feb 2019 11:39:00 -0800 (PST) Received: from ncrews2.bld.corp.google.com ([2620:15c:183:200:8140:8e3f:aea5:bcdf]) by smtp.gmail.com with ESMTPSA id o26sm1269467iob.73.2019.02.08.11.38.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 08 Feb 2019 11:38:59 -0800 (PST) From: Nick Crews To: linux-kernel@vger.kernel.org Cc: alexandre.belloni@bootlin.com, eballetbo@gmail.com, sjg@chromium.org, dmitry.torokhov@gmail.com, groeck@chromium.org, dlaurie@chromium.org, Nick Crews , Duncan Laurie , Enric Balletbo i Serra , linux-rtc@vger.kernel.org, Alessandro Zummo , Benson Leung Subject: [PATCH v7 4/4] platform/chrome: rtc: Add RTC driver Date: Fri, 8 Feb 2019 12:38:50 -0700 Message-Id: <20190208193850.120121-5-ncrews@chromium.org> X-Mailer: git-send-email 2.20.1.791.gb4d0f1c61a-goog In-Reply-To: <20190208193850.120121-1-ncrews@chromium.org> References: <20190208193850.120121-1-ncrews@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This Embedded Controller has an internal RTC that is exposed as a standard RTC class driver with read/write functionality. The driver is added to the drivers/rtc/ so that the maintainer of that directory will be able to comment on this change, as that maintainer is the expert on this system. In addition, the driver code is called indirectly after a corresponding device is registered from core.c, as opposed to core.c registering the driver callbacks directly. To test: > hwclock --show --rtc /dev/rtc1 2007-12-31 16:01:20.460959-08:00 > hwclock --systohc --rtc /dev/rtc1 > hwclock --show --rtc /dev/rtc1 2018-11-29 17:08:00.780793-08:00 > hwclock --show --rtc /dev/rtc1 2007-12-31 16:01:20.460959-08:00 > hwclock --systohc --rtc /dev/rtc1 > hwclock --show --rtc /dev/rtc1 2018-11-29 17:08:00.780793-08:00 Signed-off-by: Duncan Laurie Acked-by: Enric Balletbo i Serra Acked-by: Alexandre Belloni Signed-off-by: Nick Crews --- Changes in v7: None Changes in v6: - In the core, actually unregister the RTC child platform_device. Changes in v5: None Changes in v4: - Change me email to @chromium.org from @google.com - Move "Add RTC driver" before "Add sysfs attributes" so that it could get accepted earlier, since it is less contentious Changes in v3: - rm #define for driver name - Don't compute weekday when reading from RTC. Still set weekday when writing, as RTC needs this to control advanced power scheduling - rm check for invalid month data - Set range_min and range_max on rtc_device Changes in v2: - rm license boiler plate - rm "wilco_ec_rtc -" prefix in docstring - Make rtc driver its own module within the drivers/rtc/ directory - Register a rtc device from core.c that is picked up by this driver drivers/platform/chrome/wilco_ec/core.c | 22 ++- drivers/rtc/Kconfig | 11 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-wilco-ec.c | 177 ++++++++++++++++++++++++ include/linux/platform_data/wilco-ec.h | 2 + 5 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 drivers/rtc/rtc-wilco-ec.c diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c index ae86cae216fd..e67385ec5103 100644 --- a/drivers/platform/chrome/wilco_ec/core.c +++ b/drivers/platform/chrome/wilco_ec/core.c @@ -42,6 +42,7 @@ static int wilco_ec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct wilco_ec_device *ec; + int ret; ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); if (!ec) @@ -70,21 +71,38 @@ static int wilco_ec_probe(struct platform_device *pdev) ec->io_packet->start + EC_MAILBOX_DATA_SIZE); /* - * Register a debugfs platform device that will get picked up by the - * debugfs driver. Ignore failure. + * Register a child device that will be found by the RTC driver. + * Ignore failure. */ ec->debugfs_pdev = platform_device_register_data(dev, "wilco-ec-debugfs", PLATFORM_DEVID_AUTO, NULL, 0); + /* Register a child device that will be found by the RTC driver. */ + ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec", + PLATFORM_DEVID_AUTO, + NULL, 0); + if (IS_ERR(ec->rtc_pdev)) { + dev_err(dev, "Failed to create RTC platform device\n"); + ret = PTR_ERR(ec->rtc_pdev); + goto unregister_debugfs; + } + return 0; + +unregister_debugfs: + if (ec->debugfs_pdev) + platform_device_unregister(ec->debugfs_pdev); + cros_ec_lpc_mec_destroy(); + return ret; } static int wilco_ec_remove(struct platform_device *pdev) { struct wilco_ec_device *ec = platform_get_drvdata(pdev); + platform_device_unregister(ec->rtc_pdev); if (ec->debugfs_pdev) platform_device_unregister(ec->debugfs_pdev); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 225b0b8516f3..d5063c791515 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1814,4 +1814,15 @@ config RTC_DRV_GOLDFISH Goldfish is a code name for the virtual platform developed by Google for Android emulation. +config RTC_DRV_WILCO_EC + tristate "Wilco EC RTC" + depends on WILCO_EC + default m + help + If you say yes here, you get read/write support for the Real Time + Clock on the Wilco Embedded Controller (Wilco is a kind of Chromebook) + + This can also be built as a module. If so, the module will + be named "rtc_wilco_ec". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index df022d820bee..6255ea78da25 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -172,6 +172,7 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o +obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o diff --git a/drivers/rtc/rtc-wilco-ec.c b/drivers/rtc/rtc-wilco-ec.c new file mode 100644 index 000000000000..35cc56114c1c --- /dev/null +++ b/drivers/rtc/rtc-wilco-ec.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RTC interface for Wilco Embedded Controller with R/W abilities + * + * Copyright 2018 Google LLC + * + * The corresponding platform device is typically registered in + * drivers/platform/chrome/wilco_ec/core.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EC_COMMAND_CMOS 0x7c +#define EC_CMOS_TOD_WRITE 0x02 +#define EC_CMOS_TOD_READ 0x08 + +/** + * struct ec_rtc_read - Format of RTC returned by EC. + * @second: Second value (0..59) + * @minute: Minute value (0..59) + * @hour: Hour value (0..23) + * @day: Day value (1..31) + * @month: Month value (1..12) + * @year: Year value (full year % 100) + * @century: Century value (full year / 100) + * + * All values are presented in binary (not BCD). + */ +struct ec_rtc_read { + u8 second; + u8 minute; + u8 hour; + u8 day; + u8 month; + u8 year; + u8 century; +} __packed; + +/** + * struct ec_rtc_write - Format of RTC sent to the EC. + * @param: EC_CMOS_TOD_WRITE + * @century: Century value (full year / 100) + * @year: Year value (full year % 100) + * @month: Month value (1..12) + * @day: Day value (1..31) + * @hour: Hour value (0..23) + * @minute: Minute value (0..59) + * @second: Second value (0..59) + * @weekday: Day of the week (0=Saturday) + * + * All values are presented in BCD. + */ +struct ec_rtc_write { + u8 param; + u8 century; + u8 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 weekday; +} __packed; + +int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm) +{ + struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); + u8 param = EC_CMOS_TOD_READ; + struct ec_rtc_read rtc; + struct wilco_ec_message msg = { + .type = WILCO_EC_MSG_LEGACY, + .flags = WILCO_EC_FLAG_RAW_RESPONSE, + .command = EC_COMMAND_CMOS, + .request_data = ¶m, + .request_size = sizeof(param), + .response_data = &rtc, + .response_size = sizeof(rtc), + }; + int ret; + + ret = wilco_ec_mailbox(ec, &msg); + if (ret < 0) + return ret; + + tm->tm_sec = rtc.second; + tm->tm_min = rtc.minute; + tm->tm_hour = rtc.hour; + tm->tm_mday = rtc.day; + tm->tm_mon = rtc.month - 1; + tm->tm_year = rtc.year + (rtc.century * 100) - 1900; + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); + + /* Don't compute day of week, we don't need it. */ + tm->tm_wday = -1; + + return 0; +} + +int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm) +{ + struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); + struct ec_rtc_write rtc; + struct wilco_ec_message msg = { + .type = WILCO_EC_MSG_LEGACY, + .flags = WILCO_EC_FLAG_RAW_RESPONSE, + .command = EC_COMMAND_CMOS, + .request_data = &rtc, + .request_size = sizeof(rtc), + }; + int year = tm->tm_year + 1900; + /* + * Convert from 0=Sunday to 0=Saturday for the EC + * We DO need to set weekday because the EC controls battery charging + * schedules that depend on the day of the week. + */ + int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1; + int ret; + + rtc.param = EC_CMOS_TOD_WRITE; + rtc.century = bin2bcd(year / 100); + rtc.year = bin2bcd(year % 100); + rtc.month = bin2bcd(tm->tm_mon + 1); + rtc.day = bin2bcd(tm->tm_mday); + rtc.hour = bin2bcd(tm->tm_hour); + rtc.minute = bin2bcd(tm->tm_min); + rtc.second = bin2bcd(tm->tm_sec); + rtc.weekday = bin2bcd(wday); + + ret = wilco_ec_mailbox(ec, &msg); + if (ret < 0) + return ret; + + return 0; +} + +static const struct rtc_class_ops wilco_ec_rtc_ops = { + .read_time = wilco_ec_rtc_read, + .set_time = wilco_ec_rtc_write, +}; + +static int wilco_ec_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + + rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + rtc->ops = &wilco_ec_rtc_ops; + /* EC only supports this century */ + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; + rtc->owner = THIS_MODULE; + + return rtc_register_device(rtc); +} + +static struct platform_driver wilco_ec_rtc_driver = { + .driver = { + .name = "rtc-wilco-ec", + }, + .probe = wilco_ec_rtc_probe, +}; + +module_platform_driver(wilco_ec_rtc_driver); + +MODULE_ALIAS("platform:rtc-wilco-ec"); +MODULE_AUTHOR("Nick Crews "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Wilco EC RTC driver"); diff --git a/include/linux/platform_data/wilco-ec.h b/include/linux/platform_data/wilco-ec.h index 5344975afa1a..446473a46b88 100644 --- a/include/linux/platform_data/wilco-ec.h +++ b/include/linux/platform_data/wilco-ec.h @@ -35,6 +35,7 @@ * is used to hold the request and the response. * @data_size: Size of the data buffer used for EC communication. * @debugfs_pdev: The child platform_device used by the debugfs sub-driver. + * @rtc_pdev: The child platform_device used by the RTC sub-driver. */ struct wilco_ec_device { struct device *dev; @@ -45,6 +46,7 @@ struct wilco_ec_device { void *data_buffer; size_t data_size; struct platform_device *debugfs_pdev; + struct platform_device *rtc_pdev; }; /** -- 2.20.1.791.gb4d0f1c61a-goog