linux-loongson/include/linux/pps_gen_kernel.h
Subramanian Mohan ac9c5170a1 pps: generators: replace copy of pps-gen info struct with const pointer
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>
2025-02-21 10:46:49 +01:00

79 lines
1.9 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* PPS generator API kernel header
*
* Copyright (C) 2024 Rodolfo Giometti <giometti@enneenne.com>
*/
#ifndef LINUX_PPS_GEN_KERNEL_H
#define LINUX_PPS_GEN_KERNEL_H
#include <linux/pps_gen.h>
#include <linux/cdev.h>
#include <linux/device.h>
/*
* Global defines
*/
#define PPS_GEN_MAX_SOURCES 16 /* should be enough... */
struct pps_gen_device;
/**
* struct pps_gen_source_info - the specific PPS generator info
* @use_system_clock: true, if the system clock is used to generate pulses
* @get_time: query the time stored into the generator clock
* @enable: enable/disable the PPS pulses generation
*
* This is the main generator struct where all needed information must be
* placed before calling the pps_gen_register_source().
*/
struct pps_gen_source_info {
bool use_system_clock;
int (*get_time)(struct pps_gen_device *pps_gen,
struct timespec64 *time);
int (*enable)(struct pps_gen_device *pps_gen, bool enable);
/* private: internal use only */
struct module *owner;
struct device *parent; /* for device_create */
};
/* The main struct */
struct pps_gen_device {
const struct pps_gen_source_info *info; /* PSS generator info */
bool enabled; /* PSS generator status */
unsigned int event;
unsigned int sequence;
unsigned int last_ev; /* last PPS event id */
wait_queue_head_t queue; /* PPS event queue */
unsigned int id; /* PPS generator unique ID */
struct cdev cdev;
struct device *dev;
struct fasync_struct *async_queue; /* fasync method */
spinlock_t lock;
};
/*
* Global variables
*/
extern const struct attribute_group *pps_gen_groups[];
/*
* Exported functions
*/
extern struct pps_gen_device *pps_gen_register_source(
const struct pps_gen_source_info *info);
extern void pps_gen_unregister_source(struct pps_gen_device *pps_gen);
extern void pps_gen_event(struct pps_gen_device *pps_gen,
unsigned int event, void *data);
#endif /* LINUX_PPS_GEN_KERNEL_H */