一点记录

Core.c    drivers\Base

/**
 * device_create - creates a device and registers it with sysfs
 * @class: pointer to the struct class that this device should be registered to
 * @parent: pointer to the parent struct device of this new device, if any
 * @devt: the dev_t for the char device to be added
 * @drvdata: the data to be added to the device for callbacks
 * @fmt: string for the device's name
 *
 * This function can be used by char device classes.  A struct device
 * will be created in sysfs, registered to the specified class.
 *
 * A "dev" file will be created, showing the dev_t for the device, if
 * the dev_t is not 0,0.
 * If a pointer to a parent struct device is passed in, the newly created
 * struct device will be a child of that device in sysfs.
 * The pointer to the struct device will be returned from the call.
 * Any further sysfs files that might be required can be created using this
 * pointer.
 *
 * Returns &struct device pointer on success, or ERR_PTR() on error.
 *
 * Note: the struct class passed to this function must have previously
 * been created with a call to class_create().
 */
struct device *device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
{
    va_list vargs;
    struct device *dev;

    va_start(vargs, fmt);
    dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
    va_end(vargs);
    return dev;
}


/**
 * device_create_vargs - creates a device and registers it with sysfs
 * @class: pointer to the struct class that this device should be registered to
 * @parent: pointer to the parent struct device of this new device, if any
 * @devt: the dev_t for the char device to be added
 * @drvdata: the data to be added to the device for callbacks
 * @fmt: string for the device's name
 * @args: va_list for the device's name
 *
 * This function can be used by char device classes.  A struct device
 * will be created in sysfs, registered to the specified class.
 *
 * A "dev" file will be created, showing the dev_t for the device, if
 * the dev_t is not 0,0.
 * If a pointer to a parent struct device is passed in, the newly created
 * struct device will be a child of that device in sysfs.
 * The pointer to the struct device will be returned from the call.
 * Any further sysfs files that might be required can be created using this
 * pointer.
 *
 * Returns &struct device pointer on success, or ERR_PTR() on error.
 *
 * Note: the struct class passed to this function must have previously
 * been created with a call to class_create().
 */
struct device *device_create_vargs(struct class *class, struct device *parent,
                   dev_t devt, void *drvdata, const char *fmt,
                   va_list args)
{
    struct device *dev = NULL;
    int retval = -ENODEV;

    if (class == NULL || IS_ERR(class))
        goto error;

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev) {
        retval = -ENOMEM;
        goto error;
    }

    dev->devt = devt;
    dev->class = class;
    dev->parent = parent;
    dev->release = device_create_release;
    dev_set_drvdata(dev, drvdata);

    retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
    if (retval)
        goto error;

    retval = device_register(dev);
    if (retval)
        goto error;

    return dev;

error:
    put_device(dev);
    return ERR_PTR(retval);
}


/**
 * device_register - register a device with the system.
 * @dev: pointer to the device structure
 *
 * This happens in two clean steps - initialize the device
 * and add it to the system. The two steps can be called
 * separately, but this is the easiest and most common.
 * I.e. you should only call the two helpers separately if
 * have a clearly defined need to use and refcount the device
 * before it is added to the hierarchy.
 *
 * NOTE: _Never_ directly free @dev after calling this function, even
 * if it returned an error! Always use put_device() to give up the
 * reference initialized in this function instead.
 */
int device_register(struct device *dev)
{
    device_initialize(dev);
    return device_add(dev);
}


/**

 * device_initialize - init device structure.
 * @dev: device.
 *
 * This prepares the device for use by other layers by initializing
 * its fields.
 * It is the first half of device_register(), if called by
 * that function, though it can also be called separately, so one
 * may use @dev's fields. In particular, get_device()/put_device()
 * may be used for reference counting of @dev after calling this
 * function.
 *
 * NOTE: Use put_device() to give up your reference instead of freeing
 * @dev directly once you have called this function.
 */
void device_initialize(struct device *dev)
{
    dev->kobj.kset = devices_kset;
    kobject_init(&dev->kobj, &device_ktype);
    INIT_LIST_HEAD(&dev->dma_pools);
    mutex_init(&dev->mutex);
    lockdep_set_novalidate_class(&dev->mutex);
    spin_lock_init(&dev->devres_lock);
    INIT_LIST_HEAD(&dev->devres_head);
    device_pm_init(dev);
    set_dev_node(dev, -1);

}


Main.c    drivers\base\Power

/**
 * device_pm_init - Initialize the PM-related part of a device object.
 * @dev: Device object being initialized.
 */
void device_pm_init(struct device *dev)
{
    dev->power.is_prepared = false;
    dev->power.is_suspended = false;
    init_completion(&dev->power.completion);
    complete_all(&dev->power.completion);
    dev->power.wakeup = NULL;
    spin_lock_init(&dev->power.lock);
    pm_runtime_init(dev);
    INIT_LIST_HEAD(&dev->power.entry);
}


Runtime.c    drivers\base\Power

/**
 * pm_runtime_init - Initialize run-time PM fields in given device object.
 * @dev: Device object to initialize.
 */
void pm_runtime_init(struct device *dev)
{
    dev->power.runtime_status = RPM_SUSPENDED;
    dev->power.idle_notification = false;

    dev->power.disable_depth = 1;
    atomic_set(&dev->power.usage_count, 0);

    dev->power.runtime_error = 0;

    atomic_set(&dev->power.child_count, 0);
    pm_suspend_ignore_children(dev, false);
    dev->power.runtime_auto = true;

    dev->power.request_pending = false;
    dev->power.request = RPM_REQ_NONE;
    dev->power.deferred_resume = false;
    dev->power.accounting_timestamp = jiffies;
    INIT_WORK(&dev->power.work, pm_runtime_work);

    dev->power.timer_expires = 0;
    setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
            (unsigned long)dev);

    init_waitqueue_head(&dev->power.wait_queue);
}

/**
 * pm_runtime_work - Universal run-time PM work function.
 * @work: Work structure used for scheduling the execution of this function.
 *
 * Use @work to get the device object the work is to be done for, determine what
 * is to be done and execute the appropriate run-time PM function.
 */
static void pm_runtime_work(struct work_struct *work)
{
    struct device *dev = container_of(work, struct device, power.work);
    enum rpm_request req;

    spin_lock_irq(&dev->power.lock);

    if (!dev->power.request_pending)
        goto out;

    req = dev->power.request;
    dev->power.request = RPM_REQ_NONE;
    dev->power.request_pending = false;

    switch (req) {
    case RPM_REQ_NONE:
        break;
    case RPM_REQ_IDLE:
        rpm_idle(dev, RPM_NOWAIT);
        break;
    case RPM_REQ_SUSPEND:
        rpm_suspend(dev, RPM_NOWAIT);
        break;
    case RPM_REQ_AUTOSUSPEND:
        rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);
        break;
    case RPM_REQ_RESUME:
        rpm_resume(dev, RPM_NOWAIT);
        break;
    }

 out:
    spin_unlock_irq(&dev->power.lock);
}


/**
 * pm_suspend_timer_fn - Timer function for pm_schedule_suspend().
 * @data: Device pointer passed by pm_schedule_suspend().
 *
 * Check if the time is right and queue a suspend request.
 */
static void pm_suspend_timer_fn(unsigned long data)
{
    struct device *dev = (struct device *)data;
    unsigned long flags;
    unsigned long expires;

    spin_lock_irqsave(&dev->power.lock, flags);

    expires = dev->power.timer_expires;
    /* If 'expire' is after 'jiffies' we've been called too early. */
    if (expires > 0 && !time_after(expires, jiffies)) {
        dev->power.timer_expires = 0;
        rpm_suspend(dev, dev->power.timer_autosuspends ?
            (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
    }

    spin_unlock_irqrestore(&dev->power.lock, flags);
}



Your Driver should implement Runtime suspend/resume callbacks. Check this doc.

sample code to implement Device PM callbacks in 'struct dev_pm_ops' (as defined in linux/pm.h)

static int lcdxxx_suspend(struct device *dev)
{
    //Your Code to suspend your device
}

static int lcdxxx_resume(struct device *dev)
{
    //Your code to resume your device
}

static const struct dev_pm_ops lcd_pm_ops = {
    .suspend    = lcdxxx_suspend,
    .resume     = lcdxxx_resume,
};

struct device_driver lcd_driver = {
    ....
    .pm = &lcd_pm_ops,
    ....
}

This is just sample impl. Real Implementation depends on your requirements.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值