From patchwork Thu Mar 5 09:45:41 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 45445 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-we0-f197.google.com (mail-we0-f197.google.com [74.125.82.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 98D03204BC for ; Thu, 5 Mar 2015 09:46:07 +0000 (UTC) Received: by wevk48 with SMTP id k48sf3973783wev.0 for ; Thu, 05 Mar 2015 01:46:06 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=dOFTwk4M7sHOFUc0GV6tOp5FUbYh8FJk0VVTUNwu1r0=; b=aWrRR2YK6ziUHD2fKnclRkpITXrPxA3SLhqg+4QEtajisQLq7oDz6v9P+AzchIiMQf UAMF9i6gbMrP/Loj/FpZoFYBMVMFxpvZ9tlyxjGh6A8QJVvyCkQX//ywFEQuacv9wG0m W1MSAMi1sivdDknbgOtoYH75secBhjo+LvXczBSNPjnJ5XjhXkTCVs5F9wHeiHba0C48 qS/JsQJVXIJpZZTDZtNi0/2qgBOwrGh33kM74gRXKIBfhExJ4uuen7Kl6RtFtLW5gsiu jYlGolu8aL55Qby279KCWTM3ymEWDMuQbxsazGDrQgYVGSKrAuAE1r0pjWT9ReNy7UVU 8NHA== X-Gm-Message-State: ALoCoQkWg29z78MVTMffhviudGbcrN7aWQqm4/2KkoumADdDz3cWzMqSIhXfYliwcwMKUwU86it0 X-Received: by 10.152.21.9 with SMTP id r9mr1359223lae.0.1425548766842; Thu, 05 Mar 2015 01:46:06 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.29.225 with SMTP id n1ls301434lah.52.gmail; Thu, 05 Mar 2015 01:46:06 -0800 (PST) X-Received: by 10.152.22.200 with SMTP id g8mr6986698laf.96.1425548766349; Thu, 05 Mar 2015 01:46:06 -0800 (PST) Received: from mail-la0-f45.google.com (mail-la0-f45.google.com. [209.85.215.45]) by mx.google.com with ESMTPS id ci6si4068827lad.172.2015.03.05.01.46.06 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 Mar 2015 01:46:06 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.45 as permitted sender) client-ip=209.85.215.45; Received: by lams18 with SMTP id s18so50208101lam.11 for ; Thu, 05 Mar 2015 01:46:06 -0800 (PST) X-Received: by 10.112.162.232 with SMTP id yd8mr6968869lbb.41.1425548766220; Thu, 05 Mar 2015 01:46:06 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.35.133 with SMTP id h5csp372391lbj; Thu, 5 Mar 2015 01:46:04 -0800 (PST) X-Received: by 10.66.148.165 with SMTP id tt5mr6459239pab.38.1425548763722; Thu, 05 Mar 2015 01:46:03 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id qj1si8736333pbc.75.2015.03.05.01.46.02; Thu, 05 Mar 2015 01:46:03 -0800 (PST) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932469AbbCEJp4 (ORCPT + 28 others); Thu, 5 Mar 2015 04:45:56 -0500 Received: from mail-we0-f176.google.com ([74.125.82.176]:39218 "EHLO mail-we0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932389AbbCEJpv (ORCPT ); Thu, 5 Mar 2015 04:45:51 -0500 Received: by wesu56 with SMTP id u56so8298001wes.6 for ; Thu, 05 Mar 2015 01:45:50 -0800 (PST) X-Received: by 10.180.85.39 with SMTP id e7mr20543040wiz.90.1425548750298; Thu, 05 Mar 2015 01:45:50 -0800 (PST) Received: from srini-ThinkPad-X1-Carbon-2nd.dlink.com (host-89-242-228-249.as13285.net. [89.242.228.249]) by mx.google.com with ESMTPSA id y14sm9683218wjr.39.2015.03.05.01.45.48 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 05 Mar 2015 01:45:49 -0800 (PST) From: Srinivas Kandagatla To: linux-arm-kernel@lists.infradead.org Cc: Maxime Ripard , Rob Herring , Pawel Moll , Kumar Gala , linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Stephen Boyd , andrew@lunn.ch, Arnd Bergmann , broonie@kernel.org, Greg Kroah-Hartman , Srinivas Kandagatla Subject: [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers Date: Thu, 5 Mar 2015 09:45:41 +0000 Message-Id: <1425548741-12930-1-git-send-email-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1425548685-12887-1-git-send-email-srinivas.kandagatla@linaro.org> References: <1425548685-12887-1-git-send-email-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: srinivas.kandagatla@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.45 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , This patch adds just providers part of the framework just to enable easy review. Up until now, EEPROM drivers were stored in drivers/misc, where they all had to duplicate pretty much the same code to register a sysfs file, allow in-kernel users to access the content of the devices they were driving, etc. This was also a problem as far as other in-kernel users were involved, since the solutions used were pretty much different from on driver to another, there was a rather big abstraction leak. This introduction of this framework aims at solving this. It also introduces DT representation for consumer devices to go get the data they require (MAC Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs. Having regmap interface to this framework would give much better abstraction for eeproms on different buses. Signed-off-by: Maxime Ripard [Maxime Ripard: intial version of eeprom framework] Signed-off-by: Srinivas Kandagatla --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/eeprom/Kconfig | 20 ++++ drivers/eeprom/Makefile | 9 ++ drivers/eeprom/core.c | 208 ++++++++++++++++++++++++++++++++++++++++ include/linux/eeprom-provider.h | 47 +++++++++ 6 files changed, 287 insertions(+) create mode 100644 drivers/eeprom/Kconfig create mode 100644 drivers/eeprom/Makefile create mode 100644 drivers/eeprom/core.c create mode 100644 include/linux/eeprom-provider.h diff --git a/drivers/Kconfig b/drivers/Kconfig index c70d6e4..d7afc82 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig" source "drivers/android/Kconfig" +source "drivers/eeprom/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 527a6da..57eb5b0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS) += ras/ obj-$(CONFIG_THUNDERBOLT) += thunderbolt/ obj-$(CONFIG_CORESIGHT) += coresight/ obj-$(CONFIG_ANDROID) += android/ +obj-$(CONFIG_EEPROM) += eeprom/ diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig new file mode 100644 index 0000000..d00f7d2 --- /dev/null +++ b/drivers/eeprom/Kconfig @@ -0,0 +1,20 @@ +menuconfig EEPROM + bool "EEPROM Support" + depends on OF + select REGMAP + help + Support for EEPROM alike devices. + + This framework is designed to provide a generic interface to EEPROM + from both the Linux Kernel and the userspace. + + If unsure, say no. + +if EEPROM + +config EEPROM_DEBUG + bool "EEPROM debug support" + help + Say yes here to enable debugging support. + +endif diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile new file mode 100644 index 0000000..e130079 --- /dev/null +++ b/drivers/eeprom/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for eeprom drivers. +# + +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG + +obj-$(CONFIG_EEPROM) += core.o + +# Devices diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c new file mode 100644 index 0000000..243e466 --- /dev/null +++ b/drivers/eeprom/core.c @@ -0,0 +1,208 @@ +/* + * EEPROM framework core. + * + * Copyright (C) 2015 Srinivas Kandagatla + * Copyright (C) 2013 Maxime Ripard + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct eeprom_device { + struct regmap *regmap; + int stride; + size_t size; + + struct module *owner; + struct device dev; + int id; + atomic_t users; +}; + +static DEFINE_MUTEX(eeprom_mutex); +static DEFINE_IDA(eeprom_ida); + +#define to_eeprom(d) container_of(d, struct eeprom_device, dev) + +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t offset, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct eeprom_device *eeprom = to_eeprom(dev); + int rc; + + if (offset > eeprom->size) + return -EINVAL; + + if (offset + count > eeprom->size) + count = eeprom->size - offset; + + rc = regmap_bulk_read(eeprom->regmap, offset, + buf, count/eeprom->stride); + + if (IS_ERR_VALUE(rc)) + return rc; + + return count - count % eeprom->stride; +} + +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t offset, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct eeprom_device *eeprom = to_eeprom(dev); + int rc; + + if (offset > eeprom->size) + return -EINVAL; + + if (offset + count > eeprom->size) + count = eeprom->size - offset; + + rc = regmap_bulk_write(eeprom->regmap, offset, + buf, count/eeprom->stride); + + if (IS_ERR_VALUE(rc)) + return rc; + + return count - count % eeprom->stride; +} + +static struct bin_attribute bin_attr_eeprom = { + .attr = { + .name = "eeprom", + .mode = S_IWUSR | S_IRUGO, + }, + .read = bin_attr_eeprom_read, + .write = bin_attr_eeprom_write, +}; + +static struct bin_attribute *eeprom_bin_attributes[] = { + &bin_attr_eeprom, + NULL, +}; + +static const struct attribute_group eeprom_bin_group = { + .bin_attrs = eeprom_bin_attributes, +}; + +static const struct attribute_group *eeprom_dev_groups[] = { + &eeprom_bin_group, + NULL, +}; + +static void eeprom_release(struct device *dev) +{ + kfree(to_eeprom(dev)); +} + +static struct class eeprom_class = { + .name = "eeprom", + .dev_groups = eeprom_dev_groups, + .dev_release = eeprom_release, +}; + +/** + * eeprom_register(): Register a eeprom device for given eeprom. + * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom + * + * @eeprom: eeprom device that needs to be created + * + * The return value will be an error code on error or a zero on success. + * The eeprom_device and sysfs entery will be freed by the eeprom_unregister(). + */ + +struct eeprom_device *eeprom_register(struct eeprom_config *config) +{ + struct eeprom_device *eeprom; + int rval; + + if (!config->regmap || !config->size) { + dev_err(config->dev, "Regmap not found\n"); + return ERR_PTR(-EINVAL); + } + + eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL); + if (!eeprom) + return ERR_PTR(-ENOMEM); + + eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL); + if (eeprom->id < 0) + return ERR_PTR(eeprom->id); + + eeprom->owner = config->owner; + eeprom->regmap = config->regmap; + eeprom->stride = config->stride; + eeprom->size = config->size; + eeprom->dev.class = &eeprom_class; + eeprom->dev.parent = config->dev; + eeprom->dev.of_node = config->dev ? config->dev->of_node : NULL; + dev_set_name(&eeprom->dev, "%s%d", + config->name ? : "eeprom", config->id); + + device_initialize(&eeprom->dev); + + dev_dbg(&eeprom->dev, "Registering eeprom device %s\n", + dev_name(&eeprom->dev)); + + rval = device_add(&eeprom->dev); + if (rval) + return ERR_PTR(rval); + + return eeprom; +} +EXPORT_SYMBOL(eeprom_register); + +/** + * eeprom_unregister(): Unregister previously registered eeprom device + * + * @eeprom: Pointer to previously registered eeprom device. + * + * The return value will be an non zero on error or a zero on success. + */ +int eeprom_unregister(struct eeprom_device *eeprom) +{ + mutex_lock(&eeprom_mutex); + if (atomic_read(&eeprom->users)) { + mutex_unlock(&eeprom_mutex); + return -EBUSY; + } + + device_del(&eeprom->dev); + mutex_unlock(&eeprom_mutex); + + return 0; +} +EXPORT_SYMBOL(eeprom_unregister); + +static int eeprom_init(void) +{ + return class_register(&eeprom_class); +} + +static void eeprom_exit(void) +{ + class_unregister(&eeprom_class); +} + +subsys_initcall(eeprom_init); +module_exit(eeprom_exit); + +MODULE_AUTHOR("Srinivas Kandagatla + * Copyright (C) 2013 Maxime Ripard + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef _LINUX_EEPROM_PROVIDER_H +#define _LINUX_EEPROM_PROVIDER_H + +#include + +struct eeprom_device; + +struct eeprom_config { + struct device *dev; + struct regmap *regmap; + const char *name; + int id; + int stride; + size_t size; + struct module *owner; +}; + +#ifdef CONFIG_EEPROM + +struct eeprom_device *eeprom_register(struct eeprom_config *cfg); +int eeprom_unregister(struct eeprom_device *eeprom); + +#else + +static inline struct eeprom_device *eeprom_register(struct eeprom_config *cfg) +{ + return NULL; +} +static inline int eeprom_unregister(struct eeprom_device *eeprom) +{ + return -ENOSYS; +} + +#endif /* CONFIG_EEPROM */ + +#endif /* ifndef _LINUX_EEPROM_PROVIDER_H */