mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Some PPS generator drivers may need to retrieve a pointer to their internal data while executing the PPS generator enable() method. During the driver registration the pps_gen_device pointer is returned from the framework, and for that reason, there is difficulty in getting generator driver data back in the enable function. We won't be able to use container_of macro as it results in static assert, and we might end up in using static pointer. To solve the issue and to get back the generator driver data back, we should not copy the struct pps_gen_source_info within the struct pps_gen_device during the registration stage, but simply save the pointer of the driver one. In this manner, driver may get a pointer to their internal data as shown below: struct pps_gen_foo_data_s { ... struct pps_gen_source_info gen_info; struct pps_gen_device *pps_gen; ... }; static int __init pps_gen_foo_init(void) { struct pps_gen_foo_data_s *foo; ... foo->pps_gen = pps_gen_register_source(&foo->gen_info); ... } Then, in the enable() method, we can retrieve the pointer to the main struct by using the code below: static int pps_gen_foo_enable(struct pps_gen_device *pps_gen, bool enable) { struct pps_gen_foo_data_s *foo = container_of(pps_gen->info, struct pps_gen_foo_data_s, gen_info); ... } Signed-off-by: Rodolfo Giometti <giometti@enneenne.com> Tested-by: Subramanian Mohan <subramanian.mohan@intel.com> Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Subramanian Mohan <subramanian.mohan@intel.com> Link: https://lore.kernel.org/r/20250219040618.70962-2-subramanian.mohan@intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
75 lines
1.6 KiB
C
75 lines
1.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* PPS generators sysfs support
|
|
*
|
|
* Copyright (C) 2024 Rodolfo Giometti <giometti@enneenne.com>
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
#include <linux/pps_gen_kernel.h>
|
|
|
|
/*
|
|
* Attribute functions
|
|
*/
|
|
|
|
static ssize_t system_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct pps_gen_device *pps_gen = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%d\n", pps_gen->info->use_system_clock);
|
|
}
|
|
static DEVICE_ATTR_RO(system);
|
|
|
|
static ssize_t time_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct pps_gen_device *pps_gen = dev_get_drvdata(dev);
|
|
struct timespec64 time;
|
|
int ret;
|
|
|
|
ret = pps_gen->info->get_time(pps_gen, &time);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return sysfs_emit(buf, "%llu %09lu\n", time.tv_sec, time.tv_nsec);
|
|
}
|
|
static DEVICE_ATTR_RO(time);
|
|
|
|
static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct pps_gen_device *pps_gen = dev_get_drvdata(dev);
|
|
bool status;
|
|
int ret;
|
|
|
|
ret = kstrtobool(buf, &status);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = pps_gen->info->enable(pps_gen, status);
|
|
if (ret)
|
|
return ret;
|
|
pps_gen->enabled = status;
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_WO(enable);
|
|
|
|
static struct attribute *pps_gen_attrs[] = {
|
|
&dev_attr_enable.attr,
|
|
&dev_attr_time.attr,
|
|
&dev_attr_system.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group pps_gen_group = {
|
|
.attrs = pps_gen_attrs,
|
|
};
|
|
|
|
const struct attribute_group *pps_gen_groups[] = {
|
|
&pps_gen_group,
|
|
NULL,
|
|
};
|