cregit-Linux how code gets into the kernel

Release 4.14 drivers/spmi/spmi.c

Directory: drivers/spmi
/*
 * Copyright (c) 2012-2015, 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/kernel.h>
#include <linux/errno.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spmi.h>
#include <linux/pm_runtime.h>

#include <dt-bindings/spmi/spmi.h>

#define CREATE_TRACE_POINTS
#include <trace/events/spmi.h>


static bool is_registered;
static DEFINE_IDA(ctrl_ida);


static void spmi_dev_release(struct device *dev) { struct spmi_device *sdev = to_spmi_device(dev); kfree(sdev); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke26100.00%1100.00%
Total26100.00%1100.00%

static const struct device_type spmi_dev_type = { .release = spmi_dev_release, };
static void spmi_ctrl_release(struct device *dev) { struct spmi_controller *ctrl = to_spmi_controller(dev); ida_simple_remove(&ctrl_ida, ctrl->nr); kfree(ctrl); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke36100.00%1100.00%
Total36100.00%1100.00%

static const struct device_type spmi_ctrl_type = { .release = spmi_ctrl_release, };
static int spmi_device_match(struct device *dev, struct device_driver *drv) { if (of_driver_match_device(dev, drv)) return 1; if (drv->name) return strncmp(dev_name(dev), drv->name, SPMI_NAME_SIZE) == 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke54100.00%1100.00%
Total54100.00%1100.00%

/** * spmi_device_add() - add a device previously constructed via spmi_device_alloc() * @sdev: spmi_device to be added */
int spmi_device_add(struct spmi_device *sdev) { struct spmi_controller *ctrl = sdev->ctrl; int err; dev_set_name(&sdev->dev, "%d-%02x", ctrl->nr, sdev->usid); err = device_add(&sdev->dev); if (err < 0) { dev_err(&sdev->dev, "Can't add %s, status %d\n", dev_name(&sdev->dev), err); goto err_device_add; } dev_dbg(&sdev->dev, "device %s registered\n", dev_name(&sdev->dev)); err_device_add: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke104100.00%1100.00%
Total104100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_device_add); /** * spmi_device_remove(): remove an SPMI device * @sdev: spmi_device to be removed */
void spmi_device_remove(struct spmi_device *sdev) { device_unregister(&sdev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke18100.00%1100.00%
Total18100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_device_remove);
static inline int spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid) { int ret; if (!ctrl || !ctrl->cmd || ctrl->dev.type != &spmi_ctrl_type) return -EINVAL; ret = ctrl->cmd(ctrl, opcode, sid); trace_spmi_cmd(opcode, sid, ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke5275.36%150.00%
Ankit Gupta1724.64%150.00%
Total69100.00%2100.00%


static inline int spmi_read_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid, u16 addr, u8 *buf, size_t len) { int ret; if (!ctrl || !ctrl->read_cmd || ctrl->dev.type != &spmi_ctrl_type) return -EINVAL; trace_spmi_read_begin(opcode, sid, addr); ret = ctrl->read_cmd(ctrl, opcode, sid, addr, buf, len); trace_spmi_read_end(opcode, sid, addr, ret, len, buf); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke6868.00%150.00%
Ankit Gupta3232.00%150.00%
Total100100.00%2100.00%


static inline int spmi_write_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid, u16 addr, const u8 *buf, size_t len) { int ret; if (!ctrl || !ctrl->write_cmd || ctrl->dev.type != &spmi_ctrl_type) return -EINVAL; trace_spmi_write_begin(opcode, sid, addr, len, buf); ret = ctrl->write_cmd(ctrl, opcode, sid, addr, buf, len); trace_spmi_write_end(opcode, sid, addr, ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke6968.32%150.00%
Ankit Gupta3231.68%150.00%
Total101100.00%2100.00%

/** * spmi_register_read() - register read * @sdev: SPMI device. * @addr: slave register address (5-bit address). * @buf: buffer to be populated with data from the Slave. * * Reads 1 byte of data from a Slave device register. */
int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf) { /* 5-bit register address */ if (addr > 0x1F) return -EINVAL; return spmi_read_cmd(sdev->ctrl, SPMI_CMD_READ, sdev->usid, addr, buf, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke48100.00%1100.00%
Total48100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_register_read); /** * spmi_ext_register_read() - extended register read * @sdev: SPMI device. * @addr: slave register address (8-bit address). * @buf: buffer to be populated with data from the Slave. * @len: the request number of bytes to read (up to 16 bytes). * * Reads up to 16 bytes of data from the extended register space on a * Slave device. */
int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf, size_t len) { /* 8-bit register address, up to 16 bytes */ if (len == 0 || len > 16) return -EINVAL; return spmi_read_cmd(sdev->ctrl, SPMI_CMD_EXT_READ, sdev->usid, addr, buf, len); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_ext_register_read); /** * spmi_ext_register_readl() - extended register read long * @sdev: SPMI device. * @addr: slave register address (16-bit address). * @buf: buffer to be populated with data from the Slave. * @len: the request number of bytes to read (up to 8 bytes). * * Reads up to 8 bytes of data from the extended register space on a * Slave device using 16-bit address. */
int spmi_ext_register_readl(struct spmi_device *sdev, u16 addr, u8 *buf, size_t len) { /* 16-bit register address, up to 8 bytes */ if (len == 0 || len > 8) return -EINVAL; return spmi_read_cmd(sdev->ctrl, SPMI_CMD_EXT_READL, sdev->usid, addr, buf, len); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_ext_register_readl); /** * spmi_register_write() - register write * @sdev: SPMI device * @addr: slave register address (5-bit address). * @data: buffer containing the data to be transferred to the Slave. * * Writes 1 byte of data to a Slave device register. */
int spmi_register_write(struct spmi_device *sdev, u8 addr, u8 data) { /* 5-bit register address */ if (addr > 0x1F) return -EINVAL; return spmi_write_cmd(sdev->ctrl, SPMI_CMD_WRITE, sdev->usid, addr, &data, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke48100.00%1100.00%
Total48100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_register_write); /** * spmi_register_zero_write() - register zero write * @sdev: SPMI device. * @data: the data to be written to register 0 (7-bits). * * Writes data to register 0 of the Slave device. */
int spmi_register_zero_write(struct spmi_device *sdev, u8 data) { return spmi_write_cmd(sdev->ctrl, SPMI_CMD_ZERO_WRITE, sdev->usid, 0, &data, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke34100.00%1100.00%
Total34100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_register_zero_write); /** * spmi_ext_register_write() - extended register write * @sdev: SPMI device. * @addr: slave register address (8-bit address). * @buf: buffer containing the data to be transferred to the Slave. * @len: the request number of bytes to read (up to 16 bytes). * * Writes up to 16 bytes of data to the extended register space of a * Slave device. */
int spmi_ext_register_write(struct spmi_device *sdev, u8 addr, const u8 *buf, size_t len) { /* 8-bit register address, up to 16 bytes */ if (len == 0 || len > 16) return -EINVAL; return spmi_write_cmd(sdev->ctrl, SPMI_CMD_EXT_WRITE, sdev->usid, addr, buf, len); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke56100.00%1100.00%
Total56100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_ext_register_write); /** * spmi_ext_register_writel() - extended register write long * @sdev: SPMI device. * @addr: slave register address (16-bit address). * @buf: buffer containing the data to be transferred to the Slave. * @len: the request number of bytes to read (up to 8 bytes). * * Writes up to 8 bytes of data to the extended register space of a * Slave device using 16-bit address. */
int spmi_ext_register_writel(struct spmi_device *sdev, u16 addr, const u8 *buf, size_t len) { /* 4-bit Slave Identifier, 16-bit register address, up to 8 bytes */ if (len == 0 || len > 8) return -EINVAL; return spmi_write_cmd(sdev->ctrl, SPMI_CMD_EXT_WRITEL, sdev->usid, addr, buf, len); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke56100.00%1100.00%
Total56100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_ext_register_writel); /** * spmi_command_reset() - sends RESET command to the specified slave * @sdev: SPMI device. * * The Reset command initializes the Slave and forces all registers to * their reset values. The Slave shall enter the STARTUP state after * receiving a Reset command. */
int spmi_command_reset(struct spmi_device *sdev) { return spmi_cmd(sdev->ctrl, SPMI_CMD_RESET, sdev->usid); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke24100.00%1100.00%
Total24100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_command_reset); /** * spmi_command_sleep() - sends SLEEP command to the specified SPMI device * @sdev: SPMI device. * * The Sleep command causes the Slave to enter the user defined SLEEP state. */
int spmi_command_sleep(struct spmi_device *sdev) { return spmi_cmd(sdev->ctrl, SPMI_CMD_SLEEP, sdev->usid); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke24100.00%1100.00%
Total24100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_command_sleep); /** * spmi_command_wakeup() - sends WAKEUP command to the specified SPMI device * @sdev: SPMI device. * * The Wakeup command causes the Slave to move from the SLEEP state to * the ACTIVE state. */
int spmi_command_wakeup(struct spmi_device *sdev) { return spmi_cmd(sdev->ctrl, SPMI_CMD_WAKEUP, sdev->usid); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke24100.00%1100.00%
Total24100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_command_wakeup); /** * spmi_command_shutdown() - sends SHUTDOWN command to the specified SPMI device * @sdev: SPMI device. * * The Shutdown command causes the Slave to enter the SHUTDOWN state. */
int spmi_command_shutdown(struct spmi_device *sdev) { return spmi_cmd(sdev->ctrl, SPMI_CMD_SHUTDOWN, sdev->usid); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke24100.00%1100.00%
Total24100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_command_shutdown);
static int spmi_drv_probe(struct device *dev) { const struct spmi_driver *sdrv = to_spmi_driver(dev->driver); struct spmi_device *sdev = to_spmi_device(dev); int err; pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); err = sdrv->probe(sdev); if (err) goto fail_probe; return 0; fail_probe: pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke91100.00%1100.00%
Total91100.00%1100.00%


static int spmi_drv_remove(struct device *dev) { const struct spmi_driver *sdrv = to_spmi_driver(dev->driver); pm_runtime_get_sync(dev); sdrv->remove(to_spmi_device(dev)); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke62100.00%1100.00%
Total62100.00%1100.00%


static int spmi_drv_uevent(struct device *dev, struct kobj_uevent_env *env) { int ret; ret = of_device_uevent_modalias(dev, env); if (ret != -ENODEV) return ret; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson41100.00%1100.00%
Total41100.00%1100.00%

static struct bus_type spmi_bus_type = { .name = "spmi", .match = spmi_device_match, .probe = spmi_drv_probe, .remove = spmi_drv_remove, .uevent = spmi_drv_uevent, }; /** * spmi_controller_alloc() - Allocate a new SPMI device * @ctrl: associated controller * * Caller is responsible for either calling spmi_device_add() to add the * newly allocated controller, or calling spmi_device_put() to discard it. */
struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl) { struct spmi_device *sdev; sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); if (!sdev) return NULL; sdev->ctrl = ctrl; device_initialize(&sdev->dev); sdev->dev.parent = &ctrl->dev; sdev->dev.bus = &spmi_bus_type; sdev->dev.type = &spmi_dev_type; return sdev; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke84100.00%1100.00%
Total84100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_device_alloc); /** * spmi_controller_alloc() - Allocate a new SPMI controller * @parent: parent device * @size: size of private data * * Caller is responsible for either calling spmi_controller_add() to add the * newly allocated controller, or calling spmi_controller_put() to discard it. * The allocated private data region may be accessed via * spmi_controller_get_drvdata() */
struct spmi_controller *spmi_controller_alloc(struct device *parent, size_t size) { struct spmi_controller *ctrl; int id; if (WARN_ON(!parent)) return NULL; ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL); if (!ctrl) return NULL; device_initialize(&ctrl->dev); ctrl->dev.type = &spmi_ctrl_type; ctrl->dev.bus = &spmi_bus_type; ctrl->dev.parent = parent; ctrl->dev.of_node = parent->of_node; spmi_controller_set_drvdata(ctrl, &ctrl[1]); id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL); if (id < 0) { dev_err(parent, "unable to allocate SPMI controller identifier.\n"); spmi_controller_put(ctrl); return NULL; } ctrl->nr = id; dev_set_name(&ctrl->dev, "spmi-%d", id); dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id); return ctrl; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke184100.00%1100.00%
Total184100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_controller_alloc);
static void of_spmi_register_devices(struct spmi_controller *ctrl) { struct device_node *node; int err; if (!ctrl->dev.of_node) return; for_each_available_child_of_node(ctrl->dev.of_node, node) { struct spmi_device *sdev; u32 reg[2]; dev_dbg(&ctrl->dev, "adding child %pOF\n", node); err = of_property_read_u32_array(node, "reg", reg, 2); if (err) { dev_err(&ctrl->dev, "node %pOF err (%d) does not have 'reg' property\n", node, err); continue; } if (reg[1] != SPMI_USID) { dev_err(&ctrl->dev, "node %pOF contains unsupported 'reg' entry\n", node); continue; } if (reg[0] >= SPMI_MAX_SLAVE_ID) { dev_err(&ctrl->dev, "invalid usid on node %pOF\n", node); continue; } dev_dbg(&ctrl->dev, "read usid %02x\n", reg[0]); sdev = spmi_device_alloc(ctrl); if (!sdev) continue; sdev->dev.of_node = node; sdev->usid = (u8) reg[0]; err = spmi_device_add(sdev); if (err) { dev_err(&sdev->dev, "failure adding device. status %d\n", err); spmi_device_put(sdev); } } }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke21698.18%150.00%
Rob Herring41.82%150.00%
Total220100.00%2100.00%

/** * spmi_controller_add() - Add an SPMI controller * @ctrl: controller to be registered. * * Register a controller previously allocated via spmi_controller_alloc() with * the SPMI core. */
int spmi_controller_add(struct spmi_controller *ctrl) { int ret; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) return -EAGAIN; ret = device_add(&ctrl->dev); if (ret) return ret; if (IS_ENABLED(CONFIG_OF)) of_spmi_register_devices(ctrl); dev_dbg(&ctrl->dev, "spmi-%d registered: dev:%p\n", ctrl->nr, &ctrl->dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke7698.70%150.00%
Sudip Mukherjee11.30%150.00%
Total77100.00%2100.00%

; EXPORT_SYMBOL_GPL(spmi_controller_add); /* Remove a device associated with a controller */
static int spmi_ctrl_remove_device(struct device *dev, void *data) { struct spmi_device *spmidev = to_spmi_device(dev); if (dev->type == &spmi_dev_type) spmi_device_remove(spmidev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke42100.00%1100.00%
Total42100.00%1100.00%

/** * spmi_controller_remove(): remove an SPMI controller * @ctrl: controller to remove * * Remove a SPMI controller. Caller is responsible for calling * spmi_controller_put() to discard the allocated controller. */
void spmi_controller_remove(struct spmi_controller *ctrl) { int dummy; if (!ctrl) return; dummy = device_for_each_child(&ctrl->dev, NULL, spmi_ctrl_remove_device); device_del(&ctrl->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke41100.00%1100.00%
Total41100.00%1100.00%

EXPORT_SYMBOL_GPL(spmi_controller_remove); /** * spmi_driver_register() - Register client driver with SPMI core * @sdrv: client driver to be associated with client-device. * * This API will register the client driver with the SPMI framework. * It is typically called from the driver's module-init function. */
int __spmi_driver_register(struct spmi_driver *sdrv, struct module *owner) { sdrv->driver.bus = &spmi_bus_type; sdrv->driver.owner = owner; return driver_register(&sdrv->driver); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke2765.85%150.00%
Stephen Boyd1434.15%150.00%
Total41100.00%2100.00%

EXPORT_SYMBOL_GPL(__spmi_driver_register);
static void __exit spmi_exit(void) { bus_unregister(&spmi_bus_type); }

Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke15100.00%1100.00%
Total15100.00%1100.00%

module_exit(spmi_exit);
static int __init spmi_init(void) { int ret; ret = bus_register(&spmi_bus_type); if (ret) return ret; is_registered = true; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee1955.88%150.00%
Kenneth Heitke1544.12%150.00%
Total34100.00%2100.00%

postcore_initcall(spmi_init); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("SPMI module"); MODULE_ALIAS("platform:spmi");

Overall Contributors

PersonTokensPropCommitsCommitProp
Kenneth Heitke195491.69%114.29%
Ankit Gupta874.08%114.29%
Björn Andersson462.16%114.29%
Sudip Mukherjee241.13%114.29%
Stephen Boyd150.70%114.29%
Rob Herring40.19%114.29%
Gilad Avidov10.05%114.29%
Total2131100.00%7100.00%
Directory: drivers/spmi
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.