Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f559512 authored by Hanumant Singh's avatar Hanumant Singh
Browse files

esoc: Add back esoc files



Commit f06163e6
msm: reap unused kernel files
removes unused files from the kernel tree.
This patch mistakenly removed some of the files
that were merged by
commit 5ad7ffa1
esoc: Add external soc control framework
We add back the files that were removed from esoc.

Change-Id: I33750fed5272ce2d8e5f4b37347483920a4e8e95
Signed-off-by: default avatarHanumant Singh <hanumant@codeaurora.org>
parent 15d9b130
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_MOBICORE_SUPPORT)  += gud/

obj-$(CONFIG_CORESIGHT)		+= coresight/
obj-$(CONFIG_ESOC)		+= esoc/

obj-$(CONFIG_BIF)		+= bif/
obj-$(CONFIG_SENSORS)		+= sensors/
+8 −1
Original line number Diff line number Diff line
@@ -11,10 +11,17 @@ menuconfig ESOC

if ESOC

config ESOC_DEV
	bool "ESOC userspace interface"
	help
	  Say yes here to enable a userspace representation of the control
	  link. Userspace can register a request engine or a command engine
	  for the external soc. It can receive event notifications from the
	  control link.

config ESOC_DEBUG
	bool "ESOC debug support"
	help
	  Say yes here to enable debugging support in the ESOC framework
	  and individual esoc drivers.
endif

drivers/esoc/Makefile

0 → 100644
+6 −0
Original line number Diff line number Diff line
# generic  external soc control support

ccflags-$(CONFIG_ESOC_DEBUG)	:= -DDEBUG
obj-$(CONFIG_ESOC)	+= esoc_bus.o
obj-$(CONFIG_ESOC_DEV)	+= esoc_dev.o

drivers/esoc/esoc.h

0 → 100644
+150 −0
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * 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.
 */
#ifndef __ESOC_H__
#define __ESOC_H__

#include <linux/cdev.h>
#include <linux/completion.h>
#include <linux/esoc_ctrl.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>

#define ESOC_DEV_MAX		4
#define ESOC_NAME_LEN		20
#define ESOC_LINK_LEN		8

struct esoc_clink;
/**
 * struct esoc_eng: Engine of the esoc control link
 * @handle_clink_req: handle incoming esoc requests.
 * @handle_clink_evt: handle for esoc events.
 * @esoc_clink: pointer to esoc control link.
 */
struct esoc_eng {
	void (*handle_clink_req)(enum esoc_req req,
						struct esoc_eng *eng);
	void (*handle_clink_evt)(enum esoc_evt evt,
						struct esoc_eng *eng);
	struct esoc_clink *esoc_clink;
};

/**
 * struct esoc_clink: Representation of external esoc device
 * @name: Name of the external esoc.
 * @link_name: name of the physical link.
 * @parent: parent device.
 * @dev: device for userspace interface.
 * @id: id of the external device.
 * @owner: owner of the device.
 * @clink_ops: control operations for the control link
 * @req_eng: handle for request engine.
 * @cmd_eng: handle for command engine.
 * @clink_data: private data of esoc control link.
 * @compat_data: compat data of esoc driver.
 * @subsys_desc: descriptor for subsystem restart
 * @subsys_dev: ssr device handle.
 */
struct esoc_clink {
	const char *name;
	const char *link_name;
	struct device *parent;
	struct device dev;
	unsigned int id;
	struct module *owner;
	const struct esoc_clink_ops const *clink_ops;
	struct esoc_eng *req_eng;
	struct esoc_eng *cmd_eng;
	spinlock_t notify_lock;
	void *clink_data;
	void *compat_data;
	struct subsys_desc subsys;
	struct subsys_device *subsys_dev;
};

/**
 * struct esoc_clink_ops: Operations to control external soc
 * @cmd_exe: Execute control command
 * @get_status: Get current status, or response to previous command
 * @notify_esoc: notify external soc of events
 */
struct esoc_clink_ops {
	int (*cmd_exe)(enum esoc_cmd cmd, struct esoc_clink *dev);
	int (*get_status)(u32 *status, struct esoc_clink *dev);
	void (*notify)(enum esoc_notify notify, struct esoc_clink *dev);
};

/**
 * struct esoc_compat: Compatibility of esoc drivers.
 * @name: esoc link that driver is compatible with.
 * @data: driver data associated with esoc clink.
 */
struct esoc_compat {
	const char *name;
	void *data;
};

/**
 * struct esoc_drv: Driver for an esoc clink
 * @driver: drivers for esoc.
 * @owner: module owner of esoc driver.
 * @compat_table: compatible table for driver.
 * @compat_entries
 * @probe: probe function for esoc driver.
 */
struct esoc_drv {
	struct device_driver driver;
	struct module *owner;
	struct esoc_compat *compat_table;
	unsigned int compat_entries;
	int (*probe)(struct esoc_clink *esoc_clink);
};

#define to_esoc_clink(d) container_of(d, struct esoc_clink, dev)
#define to_esoc_drv(d) container_of(d, struct esoc_drv, driver)

extern struct bus_type esoc_bus_type;


/* Exported apis */
void esoc_dev_exit(void);
int esoc_dev_init(void);
void esoc_clink_unregister(struct esoc_clink *esoc_dev);
int esoc_clink_register(struct esoc_clink *esoc_dev);
struct esoc_clink *get_esoc_clink(int id);
void put_esoc_clink(struct esoc_clink *esoc_clink);
void *get_esoc_clink_data(struct esoc_clink *esoc);
void set_esoc_clink_data(struct esoc_clink *esoc, void *data);
void esoc_clink_evt_notify(enum esoc_evt, struct esoc_clink *esoc_dev);
void esoc_clink_queue_request(enum esoc_req req, struct esoc_clink *esoc_dev);
void esoc_for_each_dev(void *data, int (*fn)(struct device *dev,
								void *data));
int esoc_clink_register_cmd_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng);
void esoc_clink_unregister_cmd_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng);
int esoc_clink_register_req_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng);
void esoc_clink_unregister_req_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng);
int esoc_drv_register(struct esoc_drv *driver);
void esoc_set_drv_data(struct esoc_clink *esoc_clink, void *data);
void *esoc_get_drv_data(struct esoc_clink *esoc_clink);
/* ssr operations */
int esoc_clink_register_ssr(struct esoc_clink *esoc_clink);
int esoc_clink_request_ssr(struct esoc_clink *esoc_clink);
void esoc_clink_unregister_ssr(struct esoc_clink *esoc_clink);
#endif
+336 −0
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * 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 <linux/idr.h>
#include <linux/slab.h>
#include "esoc.h"

static DEFINE_IDA(esoc_ida);

/* SYSFS */
static ssize_t
esoc_name_show(struct device *dev, struct device_attribute *attr,
							char *buf)
{
	return snprintf(buf, ESOC_NAME_LEN, "%s", to_esoc_clink(dev)->name);
}

static ssize_t
esoc_link_show(struct device *dev, struct device_attribute *attr,
							char *buf)
{
	return snprintf(buf, ESOC_LINK_LEN, "%s",
				to_esoc_clink(dev)->link_name);
}

static struct device_attribute esoc_clink_attrs[] = {

	__ATTR_RO(esoc_name),
	__ATTR_RO(esoc_link),
	__ATTR_NULL,
};

static int esoc_bus_match(struct device *dev, struct device_driver *drv)
{
	struct esoc_clink *esoc_clink = to_esoc_clink(dev);

	return !memcmp(esoc_clink->name, drv->name,
					strlen(drv->name));
}

static int esoc_bus_probe(struct device *dev)
{
	int ret;
	struct esoc_clink *esoc_clink = to_esoc_clink(dev);
	struct esoc_drv *esoc_drv = to_esoc_drv(dev->driver);

	ret = esoc_drv->probe(esoc_clink);
	if (ret) {
		pr_err("failed to probe %s dev\n", esoc_clink->name);
		return ret;
	}
	return 0;
}

struct bus_type esoc_bus_type = {
	.name = "esoc",
	.match = esoc_bus_match,
	.dev_attrs = esoc_clink_attrs,
};
EXPORT_SYMBOL(esoc_bus_type);

struct device esoc_bus = {
	.init_name = "esoc-bus"
};
EXPORT_SYMBOL(esoc_bus);

/* bus accessor */
static void esoc_clink_release(struct device *dev)
{
	struct esoc_clink *esoc_clink = to_esoc_clink(dev);
	ida_simple_remove(&esoc_ida, esoc_clink->id);
	kfree(esoc_clink);
}

static int esoc_clink_match_id(struct device *dev, void *id)
{
	struct esoc_clink *esoc_clink = to_esoc_clink(dev);
	int *esoc_id = (int *)id;

	if (esoc_clink->id == *esoc_id) {
		if (!try_module_get(esoc_clink->owner))
			return 0;
		return 1;
	}
	return 0;
}

void esoc_for_each_dev(void *data, int (*fn)(struct device *dev, void *))
{
	int ret;

	ret = bus_for_each_dev(&esoc_bus_type, NULL, data, fn);
	return;
}
EXPORT_SYMBOL(esoc_for_each_dev);

struct esoc_clink *get_esoc_clink(int id)
{
	struct esoc_clink *esoc_clink;
	struct device *dev;

	dev = bus_find_device(&esoc_bus_type, NULL, &id, esoc_clink_match_id);
	if (IS_ERR(dev))
		return NULL;
	esoc_clink = to_esoc_clink(dev);
	return esoc_clink;
}
EXPORT_SYMBOL(get_esoc_clink);

void put_esoc_clink(struct esoc_clink *esoc_clink)
{
	module_put(esoc_clink->owner);
}
EXPORT_SYMBOL(put_esoc_clink);

/* ssr operations */
int esoc_clink_register_ssr(struct esoc_clink *esoc_clink)
{
	int ret;
	int len;
	char *subsys_name;

	len = strlen("esoc") + sizeof(esoc_clink->id);
	subsys_name = kzalloc(len, GFP_KERNEL);
	if (IS_ERR(subsys_name))
		return PTR_ERR(subsys_name);
	snprintf(subsys_name, len, "esoc%d", esoc_clink->id);
	esoc_clink->subsys.name = subsys_name;
	esoc_clink->subsys.dev = &esoc_clink->dev;
	esoc_clink->subsys_dev = subsys_register(&esoc_clink->subsys);
	if (IS_ERR(esoc_clink->subsys_dev)) {
		dev_err(&esoc_clink->dev, "failed to register ssr node\n");
		ret = PTR_ERR(esoc_clink->subsys_dev);
		goto subsys_err;
	}
	return 0;
subsys_err:
	kfree(subsys_name);
	return ret;
}
EXPORT_SYMBOL(esoc_clink_register_ssr);

void esoc_clink_unregister_ssr(struct esoc_clink *esoc_clink)
{
	subsys_unregister(esoc_clink->subsys_dev);
	kfree(esoc_clink->subsys.name);
}
EXPORT_SYMBOL(esoc_clink_unregister_ssr);

int esoc_clink_request_ssr(struct esoc_clink *esoc_clink)
{
	subsystem_restart_dev(esoc_clink->subsys_dev);
	return 0;
}
EXPORT_SYMBOL(esoc_clink_request_ssr);

/* bus operations */
void esoc_clink_evt_notify(enum esoc_evt evt, struct esoc_clink *esoc_clink)
{
	unsigned long flags;

	spin_lock_irqsave(&esoc_clink->notify_lock, flags);
	if (esoc_clink->req_eng && esoc_clink->req_eng->handle_clink_evt)
		esoc_clink->req_eng->handle_clink_evt(evt, esoc_clink->req_eng);
	if (esoc_clink->cmd_eng && esoc_clink->cmd_eng->handle_clink_evt)
		esoc_clink->cmd_eng->handle_clink_evt(evt, esoc_clink->cmd_eng);
	spin_unlock_irqrestore(&esoc_clink->notify_lock, flags);
}
EXPORT_SYMBOL(esoc_clink_evt_notify);

void *get_esoc_clink_data(struct esoc_clink *esoc)
{
	return esoc->clink_data;
}
EXPORT_SYMBOL(get_esoc_clink_data);

void set_esoc_clink_data(struct esoc_clink *esoc, void *data)
{
	esoc->clink_data = data;
}
EXPORT_SYMBOL(set_esoc_clink_data);

void esoc_clink_queue_request(enum esoc_req req, struct esoc_clink *esoc_clink)
{
	unsigned long flags;
	struct esoc_eng *req_eng;

	spin_lock_irqsave(&esoc_clink->notify_lock, flags);
	if (esoc_clink->req_eng != NULL) {
		req_eng = esoc_clink->req_eng;
		req_eng->handle_clink_req(req, req_eng);
	}
	spin_unlock_irqrestore(&esoc_clink->notify_lock, flags);
}
EXPORT_SYMBOL(esoc_clink_queue_request);

void esoc_set_drv_data(struct esoc_clink *esoc_clink, void *data)
{
	dev_set_drvdata(&esoc_clink->dev, data);
}
EXPORT_SYMBOL(esoc_set_drv_data);

void *esoc_get_drv_data(struct esoc_clink *esoc_clink)
{
	return dev_get_drvdata(&esoc_clink->dev);
}
EXPORT_SYMBOL(esoc_get_drv_data);

/* bus registration functions */
void esoc_clink_unregister(struct esoc_clink *esoc_clink)
{
	if (get_device(&esoc_clink->dev) != NULL) {
		device_unregister(&esoc_clink->dev);
		put_device(&esoc_clink->dev);
	}
}
EXPORT_SYMBOL(esoc_clink_unregister);

int esoc_clink_register(struct esoc_clink *esoc_clink)
{
	int id, err;
	struct device *dev;

	if (!esoc_clink->name || !esoc_clink->link_name ||
					!esoc_clink->clink_ops) {
		dev_err(esoc_clink->parent, "invalid esoc arguments\n");
		return -EINVAL;
	}
	id = ida_simple_get(&esoc_ida, 0, ESOC_DEV_MAX, GFP_KERNEL);
	if (id < 0) {
		err = id;
		goto exit_ida;
	}
	esoc_clink->id = id;
	dev = &esoc_clink->dev;
	dev->bus = &esoc_bus_type;
	dev->release = esoc_clink_release;
	if (!esoc_clink->parent)
		dev->parent = &esoc_bus;
	else
		dev->parent = esoc_clink->parent;
	dev_set_name(dev, "esoc%d", id);
	err = device_register(dev);
	if (err) {
		dev_err(esoc_clink->parent, "esoc device register failed\n");
		goto exit_ida;
	}
	spin_lock_init(&esoc_clink->notify_lock);
	return 0;
exit_ida:
	ida_simple_remove(&esoc_ida, id);
	pr_err("unable to register %s, err = %d\n", esoc_clink->name, err);
	return err;
}
EXPORT_SYMBOL(esoc_clink_register);

int esoc_clink_register_req_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng)
{
	if (esoc_clink->req_eng)
		return -EBUSY;
	if (!eng->handle_clink_req)
		return -EINVAL;
	esoc_clink->req_eng = eng;
	eng->esoc_clink = esoc_clink;
	return 0;
}
EXPORT_SYMBOL(esoc_clink_register_req_eng);

int esoc_clink_register_cmd_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng)
{
	if (esoc_clink->cmd_eng)
		return -EBUSY;
	esoc_clink->cmd_eng = eng;
	eng->esoc_clink = esoc_clink;
	return 0;
}
EXPORT_SYMBOL(esoc_clink_register_cmd_eng);

void esoc_clink_unregister_req_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng)
{
	esoc_clink->req_eng = NULL;
}
EXPORT_SYMBOL(esoc_clink_unregister_req_eng);

void esoc_clink_unregister_cmd_eng(struct esoc_clink *esoc_clink,
						struct esoc_eng *eng)
{
	esoc_clink->cmd_eng = NULL;
}
EXPORT_SYMBOL(esoc_clink_unregister_cmd_eng);

int esoc_drv_register(struct esoc_drv *driver)
{
	int ret;

	driver->driver.bus = &esoc_bus_type;
	driver->driver.probe = esoc_bus_probe;
	ret = driver_register(&driver->driver);
	if (ret)
		return ret;
	return 0;
}
EXPORT_SYMBOL(esoc_drv_register);

static int __init esoc_init(void)
{
	int ret;

	ret = device_register(&esoc_bus);
	if (ret) {
		pr_err("esoc bus device register fail\n");
		return ret;
	}
	ret = bus_register(&esoc_bus_type);
	if (ret) {
		pr_err("esoc bus register fail\n");
		return ret;
	}
	pr_debug("esoc bus registration done\n");
	return 0;
}

subsys_initcall(esoc_init);
MODULE_LICENSE("GPL v2");
Loading