mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge branch 'master' into for-next
This commit is contained in:
commit
d4263348f7
10316 changed files with 557400 additions and 217358 deletions
|
|
@ -1,10 +1,10 @@
|
|||
# Makefile for the Linux device tree
|
||||
|
||||
obj-y := core.o bus.o dd.o syscore.o \
|
||||
obj-y := component.o core.o bus.o dd.o syscore.o \
|
||||
driver.o class.o platform.o \
|
||||
cpu.o firmware.o init.o map.o devres.o \
|
||||
attribute_container.o transport_class.o \
|
||||
topology.o
|
||||
topology.o container.o
|
||||
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
|
||||
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
|
||||
obj-y += power/
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ static inline int hypervisor_init(void) { return 0; }
|
|||
#endif
|
||||
extern int platform_bus_init(void);
|
||||
extern void cpu_dev_init(void);
|
||||
extern void container_dev_init(void);
|
||||
|
||||
struct kobject *virtual_device_parent(struct device *dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -146,8 +146,19 @@ void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bus_remove_file);
|
||||
|
||||
static void bus_release(struct kobject *kobj)
|
||||
{
|
||||
struct subsys_private *priv =
|
||||
container_of(kobj, typeof(*priv), subsys.kobj);
|
||||
struct bus_type *bus = priv->bus;
|
||||
|
||||
kfree(priv);
|
||||
bus->p = NULL;
|
||||
}
|
||||
|
||||
static struct kobj_type bus_ktype = {
|
||||
.sysfs_ops = &bus_sysfs_ops,
|
||||
.release = bus_release,
|
||||
};
|
||||
|
||||
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
|
||||
|
|
@ -953,8 +964,6 @@ void bus_unregister(struct bus_type *bus)
|
|||
kset_unregister(bus->p->devices_kset);
|
||||
bus_remove_file(bus, &bus_attr_uevent);
|
||||
kset_unregister(&bus->p->subsys);
|
||||
kfree(bus->p);
|
||||
bus->p = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bus_unregister);
|
||||
|
||||
|
|
|
|||
390
drivers/base/component.c
Normal file
390
drivers/base/component.c
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* Componentized device handling.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This is work in progress. We gather up the component devices into a list,
|
||||
* and bind them when instructed. At the moment, we're specific to the DRM
|
||||
* subsystem, and only handles one master device, but this doesn't have to be
|
||||
* the case.
|
||||
*/
|
||||
#include <linux/component.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct master {
|
||||
struct list_head node;
|
||||
struct list_head components;
|
||||
bool bound;
|
||||
|
||||
const struct component_master_ops *ops;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct component {
|
||||
struct list_head node;
|
||||
struct list_head master_node;
|
||||
struct master *master;
|
||||
bool bound;
|
||||
|
||||
const struct component_ops *ops;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(component_mutex);
|
||||
static LIST_HEAD(component_list);
|
||||
static LIST_HEAD(masters);
|
||||
|
||||
static struct master *__master_find(struct device *dev,
|
||||
const struct component_master_ops *ops)
|
||||
{
|
||||
struct master *m;
|
||||
|
||||
list_for_each_entry(m, &masters, node)
|
||||
if (m->dev == dev && (!ops || m->ops == ops))
|
||||
return m;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Attach an unattached component to a master. */
|
||||
static void component_attach_master(struct master *master, struct component *c)
|
||||
{
|
||||
c->master = master;
|
||||
|
||||
list_add_tail(&c->master_node, &master->components);
|
||||
}
|
||||
|
||||
/* Detach a component from a master. */
|
||||
static void component_detach_master(struct master *master, struct component *c)
|
||||
{
|
||||
list_del(&c->master_node);
|
||||
|
||||
c->master = NULL;
|
||||
}
|
||||
|
||||
int component_master_add_child(struct master *master,
|
||||
int (*compare)(struct device *, void *), void *compare_data)
|
||||
{
|
||||
struct component *c;
|
||||
int ret = -ENXIO;
|
||||
|
||||
list_for_each_entry(c, &component_list, node) {
|
||||
if (c->master)
|
||||
continue;
|
||||
|
||||
if (compare(c->dev, compare_data)) {
|
||||
component_attach_master(master, c);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_master_add_child);
|
||||
|
||||
/* Detach all attached components from this master */
|
||||
static void master_remove_components(struct master *master)
|
||||
{
|
||||
while (!list_empty(&master->components)) {
|
||||
struct component *c = list_first_entry(&master->components,
|
||||
struct component, master_node);
|
||||
|
||||
WARN_ON(c->master != master);
|
||||
|
||||
component_detach_master(master, c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to bring up a master. If component is NULL, we're interested in
|
||||
* this master, otherwise it's a component which must be present to try
|
||||
* and bring up the master.
|
||||
*
|
||||
* Returns 1 for successful bringup, 0 if not ready, or -ve errno.
|
||||
*/
|
||||
static int try_to_bring_up_master(struct master *master,
|
||||
struct component *component)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!master->bound) {
|
||||
/*
|
||||
* Search the list of components, looking for components that
|
||||
* belong to this master, and attach them to the master.
|
||||
*/
|
||||
if (master->ops->add_components(master->dev, master)) {
|
||||
/* Failed to find all components */
|
||||
master_remove_components(master);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (component && component->master != master) {
|
||||
master_remove_components(master);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Found all components */
|
||||
ret = master->ops->bind(master->dev);
|
||||
if (ret < 0) {
|
||||
devres_release_group(master->dev, NULL);
|
||||
dev_info(master->dev, "master bind failed: %d\n", ret);
|
||||
master_remove_components(master);
|
||||
goto out;
|
||||
}
|
||||
|
||||
master->bound = true;
|
||||
ret = 1;
|
||||
}
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int try_to_bring_up_masters(struct component *component)
|
||||
{
|
||||
struct master *m;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(m, &masters, node) {
|
||||
ret = try_to_bring_up_master(m, component);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void take_down_master(struct master *master)
|
||||
{
|
||||
if (master->bound) {
|
||||
master->ops->unbind(master->dev);
|
||||
devres_release_group(master->dev, NULL);
|
||||
master->bound = false;
|
||||
}
|
||||
|
||||
master_remove_components(master);
|
||||
}
|
||||
|
||||
int component_master_add(struct device *dev,
|
||||
const struct component_master_ops *ops)
|
||||
{
|
||||
struct master *master;
|
||||
int ret;
|
||||
|
||||
master = kzalloc(sizeof(*master), GFP_KERNEL);
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
master->dev = dev;
|
||||
master->ops = ops;
|
||||
INIT_LIST_HEAD(&master->components);
|
||||
|
||||
/* Add to the list of available masters. */
|
||||
mutex_lock(&component_mutex);
|
||||
list_add(&master->node, &masters);
|
||||
|
||||
ret = try_to_bring_up_master(master, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
/* Delete off the list if we weren't successful */
|
||||
list_del(&master->node);
|
||||
kfree(master);
|
||||
}
|
||||
mutex_unlock(&component_mutex);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_master_add);
|
||||
|
||||
void component_master_del(struct device *dev,
|
||||
const struct component_master_ops *ops)
|
||||
{
|
||||
struct master *master;
|
||||
|
||||
mutex_lock(&component_mutex);
|
||||
master = __master_find(dev, ops);
|
||||
if (master) {
|
||||
take_down_master(master);
|
||||
|
||||
list_del(&master->node);
|
||||
kfree(master);
|
||||
}
|
||||
mutex_unlock(&component_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_master_del);
|
||||
|
||||
static void component_unbind(struct component *component,
|
||||
struct master *master, void *data)
|
||||
{
|
||||
WARN_ON(!component->bound);
|
||||
|
||||
component->ops->unbind(component->dev, master->dev, data);
|
||||
component->bound = false;
|
||||
|
||||
/* Release all resources claimed in the binding of this component */
|
||||
devres_release_group(component->dev, component);
|
||||
}
|
||||
|
||||
void component_unbind_all(struct device *master_dev, void *data)
|
||||
{
|
||||
struct master *master;
|
||||
struct component *c;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&component_mutex));
|
||||
|
||||
master = __master_find(master_dev, NULL);
|
||||
if (!master)
|
||||
return;
|
||||
|
||||
list_for_each_entry_reverse(c, &master->components, master_node)
|
||||
component_unbind(c, master, data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_unbind_all);
|
||||
|
||||
static int component_bind(struct component *component, struct master *master,
|
||||
void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Each component initialises inside its own devres group.
|
||||
* This allows us to roll-back a failed component without
|
||||
* affecting anything else.
|
||||
*/
|
||||
if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Also open a group for the device itself: this allows us
|
||||
* to release the resources claimed against the sub-device
|
||||
* at the appropriate moment.
|
||||
*/
|
||||
if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
|
||||
devres_release_group(master->dev, NULL);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_dbg(master->dev, "binding %s (ops %ps)\n",
|
||||
dev_name(component->dev), component->ops);
|
||||
|
||||
ret = component->ops->bind(component->dev, master->dev, data);
|
||||
if (!ret) {
|
||||
component->bound = true;
|
||||
|
||||
/*
|
||||
* Close the component device's group so that resources
|
||||
* allocated in the binding are encapsulated for removal
|
||||
* at unbind. Remove the group on the DRM device as we
|
||||
* can clean those resources up independently.
|
||||
*/
|
||||
devres_close_group(component->dev, NULL);
|
||||
devres_remove_group(master->dev, NULL);
|
||||
|
||||
dev_info(master->dev, "bound %s (ops %ps)\n",
|
||||
dev_name(component->dev), component->ops);
|
||||
} else {
|
||||
devres_release_group(component->dev, NULL);
|
||||
devres_release_group(master->dev, NULL);
|
||||
|
||||
dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
|
||||
dev_name(component->dev), component->ops, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int component_bind_all(struct device *master_dev, void *data)
|
||||
{
|
||||
struct master *master;
|
||||
struct component *c;
|
||||
int ret = 0;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&component_mutex));
|
||||
|
||||
master = __master_find(master_dev, NULL);
|
||||
if (!master)
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(c, &master->components, master_node) {
|
||||
ret = component_bind(c, master, data);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
list_for_each_entry_continue_reverse(c, &master->components,
|
||||
master_node)
|
||||
component_unbind(c, master, data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_bind_all);
|
||||
|
||||
int component_add(struct device *dev, const struct component_ops *ops)
|
||||
{
|
||||
struct component *component;
|
||||
int ret;
|
||||
|
||||
component = kzalloc(sizeof(*component), GFP_KERNEL);
|
||||
if (!component)
|
||||
return -ENOMEM;
|
||||
|
||||
component->ops = ops;
|
||||
component->dev = dev;
|
||||
|
||||
dev_dbg(dev, "adding component (ops %ps)\n", ops);
|
||||
|
||||
mutex_lock(&component_mutex);
|
||||
list_add_tail(&component->node, &component_list);
|
||||
|
||||
ret = try_to_bring_up_masters(component);
|
||||
if (ret < 0) {
|
||||
list_del(&component->node);
|
||||
|
||||
kfree(component);
|
||||
}
|
||||
mutex_unlock(&component_mutex);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_add);
|
||||
|
||||
void component_del(struct device *dev, const struct component_ops *ops)
|
||||
{
|
||||
struct component *c, *component = NULL;
|
||||
|
||||
mutex_lock(&component_mutex);
|
||||
list_for_each_entry(c, &component_list, node)
|
||||
if (c->dev == dev && c->ops == ops) {
|
||||
list_del(&c->node);
|
||||
component = c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (component && component->master)
|
||||
take_down_master(component->master);
|
||||
|
||||
mutex_unlock(&component_mutex);
|
||||
|
||||
WARN_ON(!component);
|
||||
kfree(component);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_del);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
44
drivers/base/container.c
Normal file
44
drivers/base/container.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* System bus type for containers.
|
||||
*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/container.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
#define CONTAINER_BUS_NAME "container"
|
||||
|
||||
static int trivial_online(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int container_offline(struct device *dev)
|
||||
{
|
||||
struct container_dev *cdev = to_container_dev(dev);
|
||||
|
||||
return cdev->offline ? cdev->offline(cdev) : 0;
|
||||
}
|
||||
|
||||
struct bus_type container_subsys = {
|
||||
.name = CONTAINER_BUS_NAME,
|
||||
.dev_name = CONTAINER_BUS_NAME,
|
||||
.online = trivial_online,
|
||||
.offline = container_offline,
|
||||
};
|
||||
|
||||
void __init container_dev_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = subsys_system_register(&container_subsys, NULL);
|
||||
if (ret)
|
||||
pr_err("%s() failed: %d\n", __func__, ret);
|
||||
}
|
||||
|
|
@ -491,11 +491,13 @@ static int device_add_attrs(struct device *dev)
|
|||
if (device_supports_offline(dev) && !dev->offline_disabled) {
|
||||
error = device_create_file(dev, &dev_attr_online);
|
||||
if (error)
|
||||
goto err_remove_type_groups;
|
||||
goto err_remove_dev_groups;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_dev_groups:
|
||||
device_remove_groups(dev, dev->groups);
|
||||
err_remove_type_groups:
|
||||
if (type)
|
||||
device_remove_groups(dev, type->groups);
|
||||
|
|
@ -1603,6 +1605,7 @@ device_create_groups_vargs(struct class *class, struct device *parent,
|
|||
goto error;
|
||||
}
|
||||
|
||||
device_initialize(dev);
|
||||
dev->devt = devt;
|
||||
dev->class = class;
|
||||
dev->parent = parent;
|
||||
|
|
@ -1614,7 +1617,7 @@ device_create_groups_vargs(struct class *class, struct device *parent,
|
|||
if (retval)
|
||||
goto error;
|
||||
|
||||
retval = device_register(dev);
|
||||
retval = device_add(dev);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ static int handle_remove(const char *nodename, struct device *dev)
|
|||
{
|
||||
struct path parent;
|
||||
struct dentry *dentry;
|
||||
int deleted = 1;
|
||||
int deleted = 0;
|
||||
int err;
|
||||
|
||||
dentry = kern_path_locked(nodename, &parent);
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ static inline long firmware_loading_timeout(void)
|
|||
return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
|
||||
}
|
||||
|
||||
/* firmware behavior options */
|
||||
#define FW_OPT_UEVENT (1U << 0)
|
||||
#define FW_OPT_NOWAIT (1U << 1)
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
#define FW_OPT_FALLBACK (1U << 2)
|
||||
#else
|
||||
#define FW_OPT_FALLBACK 0
|
||||
#endif
|
||||
|
||||
struct firmware_cache {
|
||||
/* firmware_buf instance will be added into the below list */
|
||||
spinlock_t lock;
|
||||
|
|
@ -219,6 +228,7 @@ static int fw_lookup_and_allocate_buf(const char *fw_name,
|
|||
}
|
||||
|
||||
static void __fw_free_buf(struct kref *ref)
|
||||
__releases(&fwc->lock)
|
||||
{
|
||||
struct firmware_buf *buf = to_fwbuf(ref);
|
||||
struct firmware_cache *fwc = buf->fwc;
|
||||
|
|
@ -270,21 +280,21 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
|
|||
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
|
||||
|
||||
/* Don't inline this: 'struct kstat' is biggish */
|
||||
static noinline_for_stack long fw_file_size(struct file *file)
|
||||
static noinline_for_stack int fw_file_size(struct file *file)
|
||||
{
|
||||
struct kstat st;
|
||||
if (vfs_getattr(&file->f_path, &st))
|
||||
return -1;
|
||||
if (!S_ISREG(st.mode))
|
||||
return -1;
|
||||
if (st.size != (long)st.size)
|
||||
if (st.size != (int)st.size)
|
||||
return -1;
|
||||
return st.size;
|
||||
}
|
||||
|
||||
static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
|
||||
{
|
||||
long size;
|
||||
int size;
|
||||
char *buf;
|
||||
int rc;
|
||||
|
||||
|
|
@ -820,7 +830,7 @@ static void firmware_class_timeout_work(struct work_struct *work)
|
|||
|
||||
static struct firmware_priv *
|
||||
fw_create_instance(struct firmware *firmware, const char *fw_name,
|
||||
struct device *device, bool uevent, bool nowait)
|
||||
struct device *device, unsigned int opt_flags)
|
||||
{
|
||||
struct firmware_priv *fw_priv;
|
||||
struct device *f_dev;
|
||||
|
|
@ -832,7 +842,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
fw_priv->nowait = nowait;
|
||||
fw_priv->nowait = !!(opt_flags & FW_OPT_NOWAIT);
|
||||
fw_priv->fw = firmware;
|
||||
INIT_DELAYED_WORK(&fw_priv->timeout_work,
|
||||
firmware_class_timeout_work);
|
||||
|
|
@ -848,8 +858,8 @@ exit:
|
|||
}
|
||||
|
||||
/* load a firmware via user helper */
|
||||
static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
|
||||
long timeout)
|
||||
static int _request_firmware_load(struct firmware_priv *fw_priv,
|
||||
unsigned int opt_flags, long timeout)
|
||||
{
|
||||
int retval = 0;
|
||||
struct device *f_dev = &fw_priv->dev;
|
||||
|
|
@ -885,7 +895,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
|
|||
goto err_del_bin_attr;
|
||||
}
|
||||
|
||||
if (uevent) {
|
||||
if (opt_flags & FW_OPT_UEVENT) {
|
||||
buf->need_uevent = true;
|
||||
dev_set_uevent_suppress(f_dev, false);
|
||||
dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
|
||||
|
|
@ -911,16 +921,16 @@ err_put_dev:
|
|||
|
||||
static int fw_load_from_user_helper(struct firmware *firmware,
|
||||
const char *name, struct device *device,
|
||||
bool uevent, bool nowait, long timeout)
|
||||
unsigned int opt_flags, long timeout)
|
||||
{
|
||||
struct firmware_priv *fw_priv;
|
||||
|
||||
fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
|
||||
fw_priv = fw_create_instance(firmware, name, device, opt_flags);
|
||||
if (IS_ERR(fw_priv))
|
||||
return PTR_ERR(fw_priv);
|
||||
|
||||
fw_priv->buf = firmware->priv;
|
||||
return _request_firmware_load(fw_priv, uevent, timeout);
|
||||
return _request_firmware_load(fw_priv, opt_flags, timeout);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
@ -942,7 +952,7 @@ static void kill_requests_without_uevent(void)
|
|||
#else /* CONFIG_FW_LOADER_USER_HELPER */
|
||||
static inline int
|
||||
fw_load_from_user_helper(struct firmware *firmware, const char *name,
|
||||
struct device *device, bool uevent, bool nowait,
|
||||
struct device *device, unsigned int opt_flags,
|
||||
long timeout)
|
||||
{
|
||||
return -ENOENT;
|
||||
|
|
@ -1023,7 +1033,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
|
|||
}
|
||||
|
||||
static int assign_firmware_buf(struct firmware *fw, struct device *device,
|
||||
bool skip_cache)
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
struct firmware_buf *buf = fw->priv;
|
||||
|
||||
|
|
@ -1040,7 +1050,8 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
|
|||
* device may has been deleted already, but the problem
|
||||
* should be fixed in devres or driver core.
|
||||
*/
|
||||
if (device && !skip_cache)
|
||||
/* don't cache firmware handled without uevent */
|
||||
if (device && (opt_flags & FW_OPT_UEVENT))
|
||||
fw_add_devm_name(device, buf->fw_id);
|
||||
|
||||
/*
|
||||
|
|
@ -1061,7 +1072,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
|
|||
/* called from request_firmware() and request_firmware_work_func() */
|
||||
static int
|
||||
_request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
struct device *device, bool uevent, bool nowait)
|
||||
struct device *device, unsigned int opt_flags)
|
||||
{
|
||||
struct firmware *fw;
|
||||
long timeout;
|
||||
|
|
@ -1076,7 +1087,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
|
||||
ret = 0;
|
||||
timeout = firmware_loading_timeout();
|
||||
if (nowait) {
|
||||
if (opt_flags & FW_OPT_NOWAIT) {
|
||||
timeout = usermodehelper_read_lock_wait(timeout);
|
||||
if (!timeout) {
|
||||
dev_dbg(device, "firmware: %s loading timed out\n",
|
||||
|
|
@ -1095,16 +1106,18 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
|
||||
ret = fw_get_filesystem_firmware(device, fw->priv);
|
||||
if (ret) {
|
||||
dev_warn(device, "Direct firmware load failed with error %d\n",
|
||||
ret);
|
||||
dev_warn(device, "Falling back to user helper\n");
|
||||
ret = fw_load_from_user_helper(fw, name, device,
|
||||
uevent, nowait, timeout);
|
||||
if (opt_flags & FW_OPT_FALLBACK) {
|
||||
dev_warn(device,
|
||||
"Direct firmware load failed with error %d\n",
|
||||
ret);
|
||||
dev_warn(device, "Falling back to user helper\n");
|
||||
ret = fw_load_from_user_helper(fw, name, device,
|
||||
opt_flags, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* don't cache firmware handled without uevent */
|
||||
if (!ret)
|
||||
ret = assign_firmware_buf(fw, device, !uevent);
|
||||
ret = assign_firmware_buf(fw, device, opt_flags);
|
||||
|
||||
usermodehelper_read_unlock();
|
||||
|
||||
|
|
@ -1146,12 +1159,37 @@ request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
|
||||
/* Need to pin this module until return */
|
||||
__module_get(THIS_MODULE);
|
||||
ret = _request_firmware(firmware_p, name, device, true, false);
|
||||
ret = _request_firmware(firmware_p, name, device,
|
||||
FW_OPT_UEVENT | FW_OPT_FALLBACK);
|
||||
module_put(THIS_MODULE);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(request_firmware);
|
||||
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
/**
|
||||
* request_firmware: - load firmware directly without usermode helper
|
||||
* @firmware_p: pointer to firmware image
|
||||
* @name: name of firmware file
|
||||
* @device: device for which firmware is being loaded
|
||||
*
|
||||
* This function works pretty much like request_firmware(), but this doesn't
|
||||
* fall back to usermode helper even if the firmware couldn't be loaded
|
||||
* directly from fs. Hence it's useful for loading optional firmwares, which
|
||||
* aren't always present, without extra long timeouts of udev.
|
||||
**/
|
||||
int request_firmware_direct(const struct firmware **firmware_p,
|
||||
const char *name, struct device *device)
|
||||
{
|
||||
int ret;
|
||||
__module_get(THIS_MODULE);
|
||||
ret = _request_firmware(firmware_p, name, device, FW_OPT_UEVENT);
|
||||
module_put(THIS_MODULE);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(request_firmware_direct);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* release_firmware: - release the resource associated with a firmware image
|
||||
* @fw: firmware resource to release
|
||||
|
|
@ -1174,7 +1212,7 @@ struct firmware_work {
|
|||
struct device *device;
|
||||
void *context;
|
||||
void (*cont)(const struct firmware *fw, void *context);
|
||||
bool uevent;
|
||||
unsigned int opt_flags;
|
||||
};
|
||||
|
||||
static void request_firmware_work_func(struct work_struct *work)
|
||||
|
|
@ -1185,7 +1223,7 @@ static void request_firmware_work_func(struct work_struct *work)
|
|||
fw_work = container_of(work, struct firmware_work, work);
|
||||
|
||||
_request_firmware(&fw, fw_work->name, fw_work->device,
|
||||
fw_work->uevent, true);
|
||||
fw_work->opt_flags);
|
||||
fw_work->cont(fw, fw_work->context);
|
||||
put_device(fw_work->device); /* taken in request_firmware_nowait() */
|
||||
|
||||
|
|
@ -1233,7 +1271,8 @@ request_firmware_nowait(
|
|||
fw_work->device = device;
|
||||
fw_work->context = context;
|
||||
fw_work->cont = cont;
|
||||
fw_work->uevent = uevent;
|
||||
fw_work->opt_flags = FW_OPT_NOWAIT | FW_OPT_FALLBACK |
|
||||
(uevent ? FW_OPT_UEVENT : 0);
|
||||
|
||||
if (!try_module_get(module)) {
|
||||
kfree(fw_work);
|
||||
|
|
|
|||
|
|
@ -33,4 +33,5 @@ void __init driver_init(void)
|
|||
platform_bus_init();
|
||||
cpu_dev_init();
|
||||
memory_dev_init();
|
||||
container_dev_init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -677,7 +677,17 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
|
|||
char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
|
||||
int len;
|
||||
|
||||
len = of_device_get_modalias(dev, buf, PAGE_SIZE -1);
|
||||
if (len != -ENODEV)
|
||||
return len;
|
||||
|
||||
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1);
|
||||
if (len != -ENODEV)
|
||||
return len;
|
||||
|
||||
len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
|
||||
|
||||
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
|
||||
}
|
||||
|
|
@ -699,6 +709,10 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
if (rc != -ENODEV)
|
||||
return rc;
|
||||
|
||||
rc = acpi_device_uevent_modalias(dev, env);
|
||||
if (rc != -ENODEV)
|
||||
return rc;
|
||||
|
||||
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
|
||||
pdev->name);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,21 @@ struct pm_clock_entry {
|
|||
enum pce_status status;
|
||||
};
|
||||
|
||||
/**
|
||||
* pm_clk_enable - Enable a clock, reporting any errors
|
||||
* @dev: The device for the given clock
|
||||
* @clk: The clock being enabled.
|
||||
*/
|
||||
static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
|
||||
{
|
||||
int ret = clk_enable(clk);
|
||||
if (ret)
|
||||
dev_err(dev, "%s: failed to enable clk %p, error %d\n",
|
||||
__func__, clk, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm_clk_acquire - Acquire a device clock.
|
||||
* @dev: Device whose clock is to be acquired.
|
||||
|
|
@ -43,6 +58,7 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
|
|||
if (IS_ERR(ce->clk)) {
|
||||
ce->status = PCE_STATUS_ERROR;
|
||||
} else {
|
||||
clk_prepare(ce->clk);
|
||||
ce->status = PCE_STATUS_ACQUIRED;
|
||||
dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
|
||||
}
|
||||
|
|
@ -99,10 +115,12 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
|
|||
|
||||
if (ce->status < PCE_STATUS_ERROR) {
|
||||
if (ce->status == PCE_STATUS_ENABLED)
|
||||
clk_disable_unprepare(ce->clk);
|
||||
clk_disable(ce->clk);
|
||||
|
||||
if (ce->status >= PCE_STATUS_ACQUIRED)
|
||||
if (ce->status >= PCE_STATUS_ACQUIRED) {
|
||||
clk_unprepare(ce->clk);
|
||||
clk_put(ce->clk);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(ce->con_id);
|
||||
|
|
@ -249,6 +267,7 @@ int pm_clk_resume(struct device *dev)
|
|||
struct pm_subsys_data *psd = dev_to_psd(dev);
|
||||
struct pm_clock_entry *ce;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "%s()\n", __func__);
|
||||
|
||||
|
|
@ -259,8 +278,9 @@ int pm_clk_resume(struct device *dev)
|
|||
|
||||
list_for_each_entry(ce, &psd->clock_list, node) {
|
||||
if (ce->status < PCE_STATUS_ERROR) {
|
||||
clk_enable(ce->clk);
|
||||
ce->status = PCE_STATUS_ENABLED;
|
||||
ret = __pm_clk_enable(dev, ce->clk);
|
||||
if (!ret)
|
||||
ce->status = PCE_STATUS_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +396,7 @@ int pm_clk_resume(struct device *dev)
|
|||
spin_lock_irqsave(&psd->lock, flags);
|
||||
|
||||
list_for_each_entry(ce, &psd->clock_list, node)
|
||||
clk_enable(ce->clk);
|
||||
__pm_clk_enable(dev, ce->clk);
|
||||
|
||||
spin_unlock_irqrestore(&psd->lock, flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
|
||||
* @dev: Device to suspend.
|
||||
|
|
@ -48,7 +48,7 @@ int pm_generic_runtime_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
|||
* OR if there is masked interrupt which hasn't been Acked,
|
||||
* it'll be ignored in irq handler, then may introduce irq storm
|
||||
*/
|
||||
if (d->mask_buf[i] && d->chip->ack_base) {
|
||||
if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
|
||||
reg = d->chip->ack_base +
|
||||
(i * map->reg_stride * d->irq_reg_stride);
|
||||
ret = regmap_write(map, reg, d->mask_buf[i]);
|
||||
|
|
@ -271,7 +271,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
|||
for (i = 0; i < data->chip->num_regs; i++) {
|
||||
data->status_buf[i] &= ~data->mask_buf[i];
|
||||
|
||||
if (data->status_buf[i] && chip->ack_base) {
|
||||
if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) {
|
||||
reg = chip->ack_base +
|
||||
(i * map->reg_stride * data->irq_reg_stride);
|
||||
ret = regmap_write(map, reg, data->status_buf[i]);
|
||||
|
|
@ -448,7 +448,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
|||
goto err_alloc;
|
||||
}
|
||||
|
||||
if (d->status_buf[i] && chip->ack_base) {
|
||||
if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
|
||||
reg = chip->ack_base +
|
||||
(i * map->reg_stride * d->irq_reg_stride);
|
||||
ret = regmap_write(map, reg,
|
||||
|
|
|
|||
|
|
@ -1514,21 +1514,49 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
|||
{
|
||||
int ret = 0, i;
|
||||
size_t val_bytes = map->format.val_bytes;
|
||||
void *wval;
|
||||
|
||||
if (!map->bus)
|
||||
return -EINVAL;
|
||||
if (!map->format.parse_inplace)
|
||||
if (map->bus && !map->format.parse_inplace)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
/*
|
||||
* Some devices don't support bulk write, for
|
||||
* them we have a series of single write operations.
|
||||
*/
|
||||
if (!map->bus || map->use_single_rw) {
|
||||
for (i = 0; i < val_count; i++) {
|
||||
unsigned int ival;
|
||||
|
||||
/* No formatting is require if val_byte is 1 */
|
||||
if (val_bytes == 1) {
|
||||
wval = (void *)val;
|
||||
switch (val_bytes) {
|
||||
case 1:
|
||||
ival = *(u8 *)(val + (i * val_bytes));
|
||||
break;
|
||||
case 2:
|
||||
ival = *(u16 *)(val + (i * val_bytes));
|
||||
break;
|
||||
case 4:
|
||||
ival = *(u32 *)(val + (i * val_bytes));
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
ival = *(u64 *)(val + (i * val_bytes));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _regmap_write(map, reg + (i * map->reg_stride),
|
||||
ival);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
void *wval;
|
||||
|
||||
wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
|
||||
if (!wval) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -1537,27 +1565,11 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
|||
}
|
||||
for (i = 0; i < val_count * val_bytes; i += val_bytes)
|
||||
map->format.parse_inplace(wval + i);
|
||||
}
|
||||
/*
|
||||
* Some devices does not support bulk write, for
|
||||
* them we have a series of single write operations.
|
||||
*/
|
||||
if (map->use_single_rw) {
|
||||
for (i = 0; i < val_count; i++) {
|
||||
ret = _regmap_raw_write(map,
|
||||
reg + (i * map->reg_stride),
|
||||
val + (i * val_bytes),
|
||||
val_bytes);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
||||
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
|
||||
}
|
||||
|
||||
if (val_bytes != 1)
|
||||
kfree(wval);
|
||||
|
||||
}
|
||||
out:
|
||||
map->unlock(map->lock_arg);
|
||||
return ret;
|
||||
|
|
@ -1897,14 +1909,10 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
|||
size_t val_bytes = map->format.val_bytes;
|
||||
bool vol = regmap_volatile_range(map, reg, val_count);
|
||||
|
||||
if (!map->bus)
|
||||
return -EINVAL;
|
||||
if (!map->format.parse_inplace)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
if (vol || map->cache_type == REGCACHE_NONE) {
|
||||
if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
|
||||
/*
|
||||
* Some devices does not support bulk read, for
|
||||
* them we have a series of single read operations.
|
||||
|
|
@ -2173,6 +2181,10 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
|
|||
int i, ret;
|
||||
bool bypass;
|
||||
|
||||
if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n",
|
||||
num_regs))
|
||||
return 0;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
bypass = map->cache_bypass;
|
||||
|
|
|
|||
Loading…
Reference in a new issue