[PATCH v2 04/31] fsi: Expose master-specific local bus clock divider

Eddie James
2024-02-26T16:53:43Z

Instead of a hardcoded local bus clock divider, allow master drivers
to select their local bus clock divider. Also expose master clock
frequencies in the structure. This will allow FSI engine drivers
to set and calculate their bus (I2C, SPI, etc) frequencies.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
drivers/fsi/fsi-core.c | 27 ++++++++++++++++++++-------
drivers/fsi/fsi-master-hub.c | 1 +
drivers/fsi/fsi-master.h | 2 ++
drivers/fsi/fsi-slave.h | 1 +
include/linux/fsi.h | 1 +
5 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 8823e8e56dab..9610b5948550 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -109,6 +109,12 @@ int fsi_device_peek(struct fsi_device *dev, void *val)
return fsi_slave_read(dev->slave, addr, val, sizeof(uint32_t));
}

+unsigned long fsi_device_local_bus_frequency(struct fsi_device *dev)
+{
+ return dev->slave->master->clock_frequency / dev->slave->master->lbus_divider;
+}
+EXPORT_SYMBOL_GPL(fsi_device_local_bus_frequency);
+
static void fsi_device_release(struct device *_device)
{
struct fsi_device *device = to_fsi_dev(_device);
@@ -209,15 +215,15 @@ static inline uint32_t fsi_smode_sid(int x)
return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
}

-static uint32_t fsi_slave_smode(int id, u8 t_senddly, u8 t_echodly)
+static uint32_t fsi_slave_smode(int id, int div, u8 t_senddly, u8 t_echodly)
{
return FSI_SMODE_WSC | FSI_SMODE_ECRC
| fsi_smode_sid(id)
| fsi_smode_echodly(t_echodly - 1) | fsi_smode_senddly(t_senddly - 1)
- | fsi_smode_lbcrr(0x8);
+ | fsi_smode_lbcrr(div - 1);
}

-static int fsi_slave_set_smode(struct fsi_slave *slave)
+static int fsi_slave_set_smode(struct fsi_slave *slave, int lbus_divider)
{
uint32_t smode;
__be32 data;
@@ -225,7 +231,8 @@ static int fsi_slave_set_smode(struct fsi_slave *slave)
/* set our smode register with the slave ID field to 0; this enables
* extended slave addressing
*/
- smode = fsi_slave_smode(slave->id, slave->t_send_delay, slave->t_echo_delay);
+ smode = fsi_slave_smode(slave->id, lbus_divider, slave->t_send_delay,
+ slave->t_echo_delay);
data = cpu_to_be32(smode);

return fsi_master_write(slave->master, slave->link, slave->id,
@@ -281,7 +288,7 @@ static int fsi_slave_handle_error(struct fsi_slave *slave, bool write,
slave->t_send_delay = send_delay;
slave->t_echo_delay = echo_delay;

- rc = fsi_slave_set_smode(slave);
+ rc = fsi_slave_set_smode(slave, master->lbus_divider);
if (rc)
return rc;

@@ -773,7 +780,7 @@ static ssize_t slave_send_echo_store(struct device *dev,
slave->t_send_delay = val;
slave->t_echo_delay = val;

- rc = fsi_slave_set_smode(slave);
+ rc = fsi_slave_set_smode(slave, master->lbus_divider);
if (rc < 0)
return rc;
if (master->link_config)
@@ -1028,7 +1035,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
"can't set slbus on slave:%02x:%02x %d\n", link, id,
rc);

- rc = fsi_slave_set_smode(slave);
+ rc = fsi_slave_set_smode(slave, master->lbus_divider);
if (rc) {
dev_warn(&master->dev,
"can't set smode on slave:%02x:%02x %d\n",
@@ -1288,6 +1295,12 @@ int fsi_master_register(struct fsi_master *master)
if (!dev_name(&master->dev))
dev_set_name(&master->dev, "fsi%d", master->idx);

+ if (master->flags & FSI_MASTER_FLAG_SWCLOCK)
+ master->clock_frequency = 100000000; // POWER reference clock
+
+ if (!master->lbus_divider)
+ master->lbus_divider = FSI_SMODE_LBCRR_DEFAULT;
+
master->dev.class = &fsi_master_class;

mutex_lock(&master->scan_lock);
diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
index 36da643b3201..111bf7a11458 100644
--- a/drivers/fsi/fsi-master-hub.c
+++ b/drivers/fsi/fsi-master-hub.c
@@ -230,6 +230,7 @@ static int hub_master_probe(struct device *dev)
hub->master.dev.release = hub_master_release;
hub->master.dev.of_node = of_node_get(dev_of_node(dev));

+ hub->master.lbus_divider = 1;
hub->master.idx = fsi_dev->slave->link + 1;
hub->master.n_links = links;
hub->master.read = hub_master_read;
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 967622c1cabf..26e636ad9ef6 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -120,6 +120,8 @@

struct fsi_master {
struct device dev;
+ unsigned long clock_frequency;
+ int lbus_divider;
int idx;
int n_links;
int flags;
diff --git a/drivers/fsi/fsi-slave.h b/drivers/fsi/fsi-slave.h
index dca9db0a42e5..42af2fae0329 100644
--- a/drivers/fsi/fsi-slave.h
+++ b/drivers/fsi/fsi-slave.h
@@ -47,6 +47,7 @@
#define FSI_SMODE_SD_DEFAULT 16 /* Default send delay */
#define FSI_SMODE_LBCRR_SHIFT 8 /* Clk ratio shift */
#define FSI_SMODE_LBCRR_MASK 0xf /* Clk ratio mask */
+#define FSI_SMODE_LBCRR_DEFAULT 8 /* Default clk ratio */

/*
* SISS fields
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index 3df8c54868df..e0309bf0ae07 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -24,6 +24,7 @@ extern int fsi_device_read(struct fsi_device *dev, uint32_t addr,
extern int fsi_device_write(struct fsi_device *dev, uint32_t addr,
const void *val, size_t size);
extern int fsi_device_peek(struct fsi_device *dev, void *val);
+extern unsigned long fsi_device_local_bus_frequency(struct fsi_device *dev);

struct fsi_device_id {
u8 engine_type;
--
2.39.3