From patchwork Mon Mar 30 21:57:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 46556 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-la0-f72.google.com (mail-la0-f72.google.com [209.85.215.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id E5279218BE for ; Mon, 30 Mar 2015 21:57:57 +0000 (UTC) Received: by lahp7 with SMTP id p7sf24507699lah.0 for ; Mon, 30 Mar 2015 14:57:56 -0700 (PDT) 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=yKRwdDV2jid1Vqs8rl7Wu/Rxgkw0RxZAqhG19xVQC3I=; b=Mh94sQiT5K/DuYf1CG/LGXE/jiKepPme1DVqyj9ll5F+KOjfhgqnOrGW9x8Ie8+0dK p5n03/7eOdxkAeW+HjIFfKGfdlQiShKUkZ3rjdILZVlMYREDgH4Vomt8sXY7EYo5qVrj f+Qrf/y0mJlms+yCNcrROQq5dwBBGjmwPmAdebdXGKphDcR5a34ihmu18X3ug9IKU4MJ xLvoh+honPZsq3n7nkV6oxH9hscFr+X6g9He80xxq9Bt0FNGqur03NJ/M/cUrCZMrAb7 FQ795Mfr2tV90nBT9PZzmhu9h+G2duMdCERwV3bTW7BhbuTb/YGyaV6tJhzH1GTaI9Be kX/Q== X-Gm-Message-State: ALoCoQm+kkuhQA/Xi1uikErZ21DbIBTfrQwa1e9tOSuz4sntW2lSlortS8GcAYEPtxsRiM0y/4IX X-Received: by 10.194.11.70 with SMTP id o6mr9064045wjb.6.1427752676900; Mon, 30 Mar 2015 14:57:56 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.36.67 with SMTP id o3ls517309laj.67.gmail; Mon, 30 Mar 2015 14:57:56 -0700 (PDT) X-Received: by 10.152.27.225 with SMTP id w1mr23334496lag.77.1427752676545; Mon, 30 Mar 2015 14:57:56 -0700 (PDT) Received: from mail-lb0-f176.google.com (mail-lb0-f176.google.com. [209.85.217.176]) by mx.google.com with ESMTPS id er4si7870012lac.131.2015.03.30.14.57.56 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 30 Mar 2015 14:57:56 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.176 as permitted sender) client-ip=209.85.217.176; Received: by lbbug6 with SMTP id ug6so104951717lbb.3 for ; Mon, 30 Mar 2015 14:57:56 -0700 (PDT) X-Received: by 10.152.197.34 with SMTP id ir2mr1797136lac.36.1427752676419; Mon, 30 Mar 2015 14:57:56 -0700 (PDT) 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.57.201 with SMTP id k9csp1410207lbq; Mon, 30 Mar 2015 14:57:55 -0700 (PDT) X-Received: by 10.70.98.193 with SMTP id ek1mr49587607pdb.65.1427752674123; Mon, 30 Mar 2015 14:57:54 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id tu4si16460143pab.237.2015.03.30.14.57.53; Mon, 30 Mar 2015 14:57:54 -0700 (PDT) Received-SPF: none (google.com: devicetree-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 S932076AbbC3V5w (ORCPT + 5 others); Mon, 30 Mar 2015 17:57:52 -0400 Received: from mail-wi0-f180.google.com ([209.85.212.180]:38359 "EHLO mail-wi0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753822AbbC3V5s (ORCPT ); Mon, 30 Mar 2015 17:57:48 -0400 Received: by wibgn9 with SMTP id gn9so2389761wib.1 for ; Mon, 30 Mar 2015 14:57:46 -0700 (PDT) X-Received: by 10.195.11.73 with SMTP id eg9mr66253618wjd.62.1427752666838; Mon, 30 Mar 2015 14:57:46 -0700 (PDT) Received: from srini-ThinkPad-X1-Carbon-2nd.dlink.com (host-78-145-247-151.as13285.net. [78.145.247.151]) by mx.google.com with ESMTPSA id a13sm17521414wjx.30.2015.03.30.14.57.44 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 30 Mar 2015 14:57:46 -0700 (PDT) From: Srinivas Kandagatla To: linux-arm-kernel@lists.infradead.org Cc: Maxime Ripard , Rob Herring , Kumar Gala , Mark Brown , s.hauer@pengutronix.de, Greg Kroah-Hartman , linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, arnd@arndb.de, sboyd@codeaurora.org, Srinivas Kandagatla Subject: [PATCH v4 03/10] eeprom: Add a simple EEPROM framework for eeprom providers Date: Mon, 30 Mar 2015 22:57:42 +0100 Message-Id: <1427752662-17173-1-git-send-email-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1427752492-17039-1-git-send-email-srinivas.kandagatla@linaro.org> References: <1427752492-17039-1-git-send-email-srinivas.kandagatla@linaro.org> Sender: devicetree-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: devicetree@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.217.176 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 | 10 ++ drivers/eeprom/Makefile | 6 ++ drivers/eeprom/core.c | 233 ++++++++++++++++++++++++++++++++++++++++ include/linux/eeprom-provider.h | 43 ++++++++ 6 files changed, 295 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 7d233c1..6767a2f 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..15985e1 --- /dev/null +++ b/drivers/eeprom/Kconfig @@ -0,0 +1,10 @@ +menuconfig EEPROM + tristate "EEPROM Support" + 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. diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile new file mode 100644 index 0000000..51a727f --- /dev/null +++ b/drivers/eeprom/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for eeprom drivers. +# + +obj-$(CONFIG_EEPROM) += eeprom_core.o +eeprom_core-y := core.o diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c new file mode 100644 index 0000000..a2c7e6c --- /dev/null +++ b/drivers/eeprom/core.c @@ -0,0 +1,233 @@ +/* + * EEPROM framework core. + * + * Copyright (C) 2015 Srinivas Kandagatla + * Copyright (C) 2013 Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct eeprom_device { + struct regmap *regmap; + int stride; + int word_size; + size_t size; + + struct module *owner; + struct device dev; + int id; + int 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 pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct eeprom_device *eeprom = to_eeprom(dev); + int rc; + + /* Stop the user from reading */ + if (pos > eeprom->size) + return 0; + + if (pos + count > eeprom->size) + count = eeprom->size - pos; + + count = count/eeprom->word_size * eeprom->word_size; + + rc = regmap_raw_read(eeprom->regmap, pos, buf, count); + + if (IS_ERR_VALUE(rc)) + return rc; + + return count; +} + +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct eeprom_device *eeprom = to_eeprom(dev); + int rc; + + /* Stop the user from writing */ + if (pos > eeprom->size) + return 0; + + if (pos + count > eeprom->size) + count = eeprom->size - pos; + + count = count/eeprom->word_size * eeprom->word_size; + + rc = regmap_raw_write(eeprom->regmap, pos, buf, count); + + if (IS_ERR_VALUE(rc)) + return rc; + + return count; +} + +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) +{ + struct eeprom_device *eeprom = to_eeprom(dev); + + ida_simple_remove(&eeprom_ida, eeprom->id); + kfree(eeprom); +} + +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 ERR_PTR() on error or a valid pointer + * to eeprom_device. + */ + +struct eeprom_device *eeprom_register(struct eeprom_config *config) +{ + struct eeprom_device *eeprom; + struct regmap *rm; + int rval; + + if (!config->dev) + return ERR_PTR(-EINVAL); + + rm = dev_get_regmap(config->dev, NULL); + if (!rm) { + 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) { + kfree(eeprom); + return ERR_PTR(eeprom->id); + } + + eeprom->regmap = rm; + eeprom->owner = config->owner; + eeprom->stride = regmap_get_reg_stride(rm); + eeprom->word_size = regmap_get_val_bytes(rm); + eeprom->size = regmap_get_max_register(rm) + eeprom->stride; + 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) { + ida_simple_remove(&eeprom_ida, eeprom->id); + kfree(eeprom); + return ERR_PTR(rval); + } + + return eeprom; +} +EXPORT_SYMBOL_GPL(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 (eeprom->users) { + mutex_unlock(&eeprom_mutex); + return -EBUSY; + } + mutex_unlock(&eeprom_mutex); + + device_del(&eeprom->dev); + + return 0; +} +EXPORT_SYMBOL_GPL(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 + +struct eeprom_device; + +struct eeprom_config { + struct device *dev; + const char *name; + int id; + struct module *owner; +}; + +#if IS_ENABLED(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 ERR_PTR(-ENOSYS); +} + +static inline int eeprom_unregister(struct eeprom_device *eeprom) +{ + return -ENOSYS; +} + +#endif /* CONFIG_EEPROM */ + +#endif /* ifndef _LINUX_EEPROM_PROVIDER_H */