net: dsa: microchip: ksz9477: add sysfs reg access support
This commit adds sysfs support for ksz9477 register acccess in
userspace. Although access is possible through the use of regmap it
showed to be uncomfortable to work with whole register dumps and also
or security reasons write access is prohibited by deault.
Do a 16-bit read access:
echo 16 0x040C > ksz_read
A 32-bit wirte access:
echo 32 0x0120 0x0115 > ksz_write
Results will be logged in the kernel buffer.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
This commit is contained in:
@@ -39,3 +39,10 @@ config NET_DSA_MICROCHIP_KSZ8863_SMI
|
||||
help
|
||||
Select to enable support for registering switches configured through
|
||||
Microchip SMI. It supports the KSZ8863 and KSZ8873 switch.
|
||||
|
||||
config NET_DSA_MICROCHIP_KSZ9477_SYSFS
|
||||
tristate "SYSFS interface for userspace KSZ register access"
|
||||
depends on NET_DSA_MICROCHIP_KSZ_COMMON
|
||||
help
|
||||
Select to enable support for accessing KSZ registers in userspace
|
||||
through the sysfs interface.
|
||||
|
||||
@@ -15,3 +15,4 @@ ksz_switch-objs += ksz_devlink.o
|
||||
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o
|
||||
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI) += ksz_spi.o
|
||||
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o
|
||||
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SYSFS) += ksz9477_sysfs.o
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ksz9477_reg.h"
|
||||
#include "ksz_common.h"
|
||||
#include "ksz9477.h"
|
||||
#include "ksz9477_sysfs.h"
|
||||
|
||||
static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
|
||||
{
|
||||
@@ -1185,6 +1186,10 @@ int ksz9477_switch_init(struct ksz_device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_NET_DSA_MICROCHIP_KSZ9477_SYSFS
|
||||
ksz_sysfs_register(dev);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* KSZ9477 Sysfs Register Access
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "ksz_common.h"
|
||||
#include "ksz9477_reg.h"
|
||||
#include "ksz9477_sysfs.h"
|
||||
|
||||
#define to_kszdev(d) container_of(d, struct ksz_device, dev)
|
||||
|
||||
struct ksz_device *g_kdev = NULL;
|
||||
|
||||
static ssize_t ksz_read_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u32 reg, value;
|
||||
int ret, bit;
|
||||
char end;
|
||||
|
||||
if (!g_kdev)
|
||||
return -EINVAL;
|
||||
|
||||
/* Parse remaining parameters, reject extra parameters */
|
||||
ret = sscanf(buf, "%d %x%c", &bit, ®, &end);
|
||||
if (ret < 1) {
|
||||
dev_err(dev, "%s: Can't parse REG address\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret > 1 && end != '\n') {
|
||||
dev_err(dev, "%s: Extra parameters\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch(bit) {
|
||||
case 8:
|
||||
ret = ksz_read8(g_kdev, reg, (u8*)&value);
|
||||
break;
|
||||
case 16:
|
||||
ret = ksz_read16(g_kdev, reg, (u16*)&value);
|
||||
break;
|
||||
case 32:
|
||||
ret = ksz_read32(g_kdev, reg, &value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: read failed.\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "%d-bit read: reg 0x%04x: 0x%08x.\n", bit, reg, value);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(ksz_read);
|
||||
|
||||
static ssize_t ksz_write_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u32 reg, value;
|
||||
int ret, bit;
|
||||
char end;
|
||||
|
||||
if (!g_kdev)
|
||||
return -EINVAL;
|
||||
|
||||
/* Parse remaining parameters, reject extra parameters */
|
||||
ret = sscanf(buf, "%d %x %x%c", &bit, ®, &value, &end);
|
||||
if (ret < 1) {
|
||||
dev_err(dev, "%s: Can't parse register command\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret > 1 && end != '\n') {
|
||||
dev_err(dev, "%s: Extra parameters\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch(bit) {
|
||||
case 8:
|
||||
ret = ksz_write8(g_kdev, reg, (u8)value);
|
||||
break;
|
||||
case 16:
|
||||
ret = ksz_write16(g_kdev, reg, (u16)value);
|
||||
break;
|
||||
case 32:
|
||||
ret = ksz_write32(g_kdev, reg, value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: read failed.\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "%d-bit write: reg 0x%04x value 0x%08x.\n",
|
||||
bit, reg, value);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(ksz_write);
|
||||
|
||||
int ksz_sysfs_register(struct ksz_device *kdev)
|
||||
{
|
||||
struct device *dev = kdev->dev;
|
||||
int ret;
|
||||
|
||||
if (!kdev)
|
||||
return -EINVAL;
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_ksz_read);
|
||||
if (ret)
|
||||
dev_err(dev, "Could not create <%s> attribute.\n", "ksz_read");
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_ksz_write);
|
||||
if (ret)
|
||||
dev_err(dev, "Could not create <%s> attribute.\n", "ksz_write");
|
||||
|
||||
g_kdev = kdev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ksz_sysfs_unregister(struct ksz_device *kdev)
|
||||
{
|
||||
struct device *dev = kdev->dev;
|
||||
|
||||
g_kdev = NULL;
|
||||
|
||||
device_remove_file(dev, &dev_attr_ksz_read);
|
||||
device_remove_file(dev, &dev_attr_ksz_write);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef KSZ9477_SYSFS_H_
|
||||
#define KSZ9477_SYSFS_H_
|
||||
|
||||
int ksz_sysfs_register(struct ksz_device *kdev);
|
||||
void ksz_sysfs_unregister(struct ksz_device *kdev);
|
||||
|
||||
#endif /* KSZ9477_SYSFS_H_ */
|
||||
Reference in New Issue
Block a user