Commit 82c944d0 authored by Herve Codina's avatar Herve Codina Committed by Linus Walleij

net: wan: Add framer framework support

A framer is a component in charge of an E1/T1 line interface.
Connected usually to a TDM bus, it converts TDM frames to/from E1/T1
frames. It also provides information related to the E1/T1 line.

The framer framework provides a set of APIs for the framer drivers
(framer provider) to create/destroy a framer and APIs for the framer
users (framer consumer) to obtain a reference to the framer, and
use the framer.

This basic implementation provides a framer abstraction for:
 - power on/off the framer
 - get the framer status (line state)
 - be notified on framer status changes
 - get/set the framer configuration
Signed-off-by: default avatarHerve Codina <herve.codina@bootlin.com>
Reviewed-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/r/20231128132534.258459-2-herve.codina@bootlin.comSigned-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent b85ea95d
......@@ -95,6 +95,8 @@ config HDLC_X25
comment "X.25/LAPB support is disabled"
depends on HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y
source "drivers/net/wan/framer/Kconfig"
config PCI200SYN
tristate "Goramo PCI200SYN support"
depends on HDLC && PCI
......
......@@ -14,6 +14,8 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
obj-y += framer/
obj-$(CONFIG_FARSYNC) += farsync.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
......
# SPDX-License-Identifier: GPL-2.0-only
#
# FRAMER
#
menuconfig FRAMER
tristate "Framer Subsystem"
help
A framer is a component in charge of an E1/T1 line interface.
Connected usually to a TDM bus, it converts TDM frames to/from E1/T1
frames. It also provides information related to the E1/T1 line.
Used with HDLC, the network can be reached through the E1/T1 line.
This framework is designed to provide a generic interface for framer
devices present in the kernel. This layer will have the generic
API by which framer drivers can create framer using the framer
framework and framer users can obtain reference to the framer.
All the users of this framework should select this config.
if FRAMER
config GENERIC_FRAMER
bool
endif # FRAMER
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the framer drivers.
#
obj-$(CONFIG_GENERIC_FRAMER) += framer-core.o
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Generic framer profider header file
*
* Copyright 2023 CS GROUP France
*
* Author: Herve Codina <herve.codina@bootlin.com>
*/
#ifndef __DRIVERS_PROVIDER_FRAMER_H
#define __DRIVERS_PROVIDER_FRAMER_H
#include <linux/export.h>
#include <linux/framer/framer.h>
#include <linux/types.h>
#define FRAMER_FLAG_POLL_STATUS BIT(0)
/**
* struct framer_ops - set of function pointers for performing framer operations
* @init: operation to be performed for initializing the framer
* @exit: operation to be performed while exiting
* @power_on: powering on the framer
* @power_off: powering off the framer
* @flags: OR-ed flags (FRAMER_FLAG_*) to ask for core functionality
* - @FRAMER_FLAG_POLL_STATUS:
* Ask the core to perform a polling to get the framer status and
* notify consumers on change.
* The framer should call @framer_notify_status_change() when it
* detects a status change. This is usually done using interrupts.
* If the framer cannot detect this change, it can ask the core for
* a status polling. The core will call @get_status() periodically
* and, on change detected, it will notify the consumer.
* the @get_status()
* @owner: the module owner containing the ops
*/
struct framer_ops {
int (*init)(struct framer *framer);
void (*exit)(struct framer *framer);
int (*power_on)(struct framer *framer);
int (*power_off)(struct framer *framer);
/**
* @get_status:
*
* Optional.
*
* Used to get the framer status. framer_init() must have
* been called on the framer.
*
* Returns: 0 if successful, an negative error code otherwise
*/
int (*get_status)(struct framer *framer, struct framer_status *status);
/**
* @set_config:
*
* Optional.
*
* Used to set the framer configuration. framer_init() must have
* been called on the framer.
*
* Returns: 0 if successful, an negative error code otherwise
*/
int (*set_config)(struct framer *framer, const struct framer_config *config);
/**
* @get_config:
*
* Optional.
*
* Used to get the framer configuration. framer_init() must have
* been called on the framer.
*
* Returns: 0 if successful, an negative error code otherwise
*/
int (*get_config)(struct framer *framer, struct framer_config *config);
u32 flags;
struct module *owner;
};
/**
* struct framer_provider - represents the framer provider
* @dev: framer provider device
* @children: can be used to override the default (dev->of_node) child node
* @owner: the module owner having of_xlate
* @list: to maintain a linked list of framer providers
* @of_xlate: function pointer to obtain framer instance from framer pointer
*/
struct framer_provider {
struct device *dev;
struct module *owner;
struct list_head list;
struct framer * (*of_xlate)(struct device *dev,
struct of_phandle_args *args);
};
static inline void framer_set_drvdata(struct framer *framer, void *data)
{
dev_set_drvdata(&framer->dev, data);
}
static inline void *framer_get_drvdata(struct framer *framer)
{
return dev_get_drvdata(&framer->dev);
}
#if IS_ENABLED(CONFIG_GENERIC_FRAMER)
/* Create and destroy a framer */
struct framer *framer_create(struct device *dev, struct device_node *node,
const struct framer_ops *ops);
void framer_destroy(struct framer *framer);
/* devm version */
struct framer *devm_framer_create(struct device *dev, struct device_node *node,
const struct framer_ops *ops);
struct framer *framer_provider_simple_of_xlate(struct device *dev,
struct of_phandle_args *args);
struct framer_provider *
__framer_provider_of_register(struct device *dev, struct module *owner,
struct framer *(*of_xlate)(struct device *dev,
struct of_phandle_args *args));
void framer_provider_of_unregister(struct framer_provider *framer_provider);
struct framer_provider *
__devm_framer_provider_of_register(struct device *dev, struct module *owner,
struct framer *(*of_xlate)(struct device *dev,
struct of_phandle_args *args));
void framer_notify_status_change(struct framer *framer);
#else /* IS_ENABLED(CONFIG_GENERIC_FRAMER) */
static inline struct framer *framer_create(struct device *dev, struct device_node *node,
const struct framer_ops *ops)
{
return ERR_PTR(-ENOSYS);
}
static inline void framer_destroy(struct framer *framer)
{
}
/* devm version */
static inline struct framer *devm_framer_create(struct device *dev, struct device_node *node,
const struct framer_ops *ops)
{
return ERR_PTR(-ENOSYS);
}
static inline struct framer *framer_provider_simple_of_xlate(struct device *dev,
struct of_phandle_args *args)
{
return ERR_PTR(-ENOSYS);
}
static inline struct framer_provider *
__framer_provider_of_register(struct device *dev, struct module *owner,
struct framer *(*of_xlate)(struct device *dev,
struct of_phandle_args *args))
{
return ERR_PTR(-ENOSYS);
}
void framer_provider_of_unregister(struct framer_provider *framer_provider)
{
}
static inline struct framer_provider *
__devm_framer_provider_of_register(struct device *dev, struct module *owner,
struct framer *(*of_xlate)(struct device *dev,
struct of_phandle_args *args))
{
return ERR_PTR(-ENOSYS);
}
void framer_notify_status_change(struct framer *framer)
{
}
#endif /* IS_ENABLED(CONFIG_GENERIC_FRAMER) */
#define framer_provider_of_register(dev, xlate) \
__framer_provider_of_register((dev), THIS_MODULE, (xlate))
#define devm_framer_provider_of_register(dev, xlate) \
__devm_framer_provider_of_register((dev), THIS_MODULE, (xlate))
#endif /* __DRIVERS_PROVIDER_FRAMER_H */
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Generic framer header file
*
* Copyright 2023 CS GROUP France
*
* Author: Herve Codina <herve.codina@bootlin.com>
*/
#ifndef __DRIVERS_FRAMER_H
#define __DRIVERS_FRAMER_H
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/device.h>
#include <linux/workqueue.h>
/**
* enum framer_iface - Framer interface
* @FRAMER_IFACE_E1: E1 interface
* @FRAMER_IFACE_T1: T1 interface
*/
enum framer_iface {
FRAMER_IFACE_E1,
FRAMER_IFACE_T1,
};
/**
* enum framer_clock_type - Framer clock type
* @FRAMER_CLOCK_EXT: External clock
* @FRAMER_CLOCK_INT: Internal clock
*/
enum framer_clock_type {
FRAMER_CLOCK_EXT,
FRAMER_CLOCK_INT,
};
/**
* struct framer_config - Framer configuration
* @iface: Framer line interface
* @clock_type: Framer clock type
* @line_clock_rate: Framer line clock rate
*/
struct framer_config {
enum framer_iface iface;
enum framer_clock_type clock_type;
unsigned long line_clock_rate;
};
/**
* struct framer_status - Framer status
* @link_is_on: Framer link state. true, the link is on, false, the link is off.
*/
struct framer_status {
bool link_is_on;
};
/**
* enum framer_event - Event available for notification
* @FRAMER_EVENT_STATUS: Event notified on framer_status changes
*/
enum framer_event {
FRAMER_EVENT_STATUS,
};
/**
* struct framer - represents the framer device
* @dev: framer device
* @id: id of the framer device
* @ops: function pointers for performing framer operations
* @mutex: mutex to protect framer_ops
* @init_count: used to protect when the framer is used by multiple consumers
* @power_count: used to protect when the framer is used by multiple consumers
* @pwr: power regulator associated with the framer
* @notify_status_work: work structure used for status notifications
* @notifier_list: notifier list used for notifications
* @polling_work: delayed work structure used for the polling task
* @prev_status: previous read status used by the polling task to detect changes
*/
struct framer {
struct device dev;
int id;
const struct framer_ops *ops;
struct mutex mutex; /* Protect framer */
int init_count;
int power_count;
struct regulator *pwr;
struct work_struct notify_status_work;
struct blocking_notifier_head notifier_list;
struct delayed_work polling_work;
struct framer_status prev_status;
};
#if IS_ENABLED(CONFIG_GENERIC_FRAMER)
int framer_pm_runtime_get(struct framer *framer);
int framer_pm_runtime_get_sync(struct framer *framer);
int framer_pm_runtime_put(struct framer *framer);
int framer_pm_runtime_put_sync(struct framer *framer);
int framer_init(struct framer *framer);
int framer_exit(struct framer *framer);
int framer_power_on(struct framer *framer);
int framer_power_off(struct framer *framer);
int framer_get_status(struct framer *framer, struct framer_status *status);
int framer_get_config(struct framer *framer, struct framer_config *config);
int framer_set_config(struct framer *framer, const struct framer_config *config);
int framer_notifier_register(struct framer *framer, struct notifier_block *nb);
int framer_notifier_unregister(struct framer *framer, struct notifier_block *nb);
struct framer *framer_get(struct device *dev, const char *con_id);
void framer_put(struct device *dev, struct framer *framer);
struct framer *devm_framer_get(struct device *dev, const char *con_id);
struct framer *devm_framer_optional_get(struct device *dev, const char *con_id);
#else
static inline int framer_pm_runtime_get(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_pm_runtime_get_sync(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_pm_runtime_put(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_pm_runtime_put_sync(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_init(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_exit(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_power_on(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_power_off(struct framer *framer)
{
return -ENOSYS;
}
static inline int framer_get_status(struct framer *framer, struct framer_status *status)
{
return -ENOSYS;
}
static inline int framer_get_config(struct framer *framer, struct framer_config *config)
{
return -ENOSYS;
}
static inline int framer_set_config(struct framer *framer, const struct framer_config *config)
{
return -ENOSYS;
}
static inline int framer_notifier_register(struct framer *framer,
struct notifier_block *nb)
{
return -ENOSYS;
}
static inline int framer_notifier_unregister(struct framer *framer,
struct notifier_block *nb)
{
return -ENOSYS;
}
struct framer *framer_get(struct device *dev, const char *con_id)
{
return ERR_PTR(-ENOSYS);
}
void framer_put(struct device *dev, struct framer *framer)
{
}
static inline struct framer *devm_framer_get(struct device *dev, const char *con_id)
{
return ERR_PTR(-ENOSYS);
}
static inline struct framer *devm_framer_optional_get(struct device *dev, const char *con_id)
{
return NULL;
}
#endif
#endif /* __DRIVERS_FRAMER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment