[PATCH 2/4] w1: ds1wm: Add device tree support
From: Julian Haller
Date: Thu Jun 30 2022 - 07:27:00 EST
From: Julian Haller <julian.haller@xxxxxxxxxxx>
The ds1wm driver now supports both, initialization with platform_data
and initialization via device tree.
Signed-off-by: Julian Haller <julian.haller@xxxxxxxxxxx>
---
drivers/w1/masters/ds1wm.c | 122 +++++++++++++++++++++++++++++++------
1 file changed, 102 insertions(+), 20 deletions(-)
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 0ecb14772f30..a764b016758f 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -22,6 +22,9 @@
#include <linux/mfd/core.h>
#include <linux/mfd/ds1wm.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/io.h>
@@ -97,6 +100,7 @@ struct ds1wm_data {
void __iomem *map;
unsigned int bus_shift; /* # of shifts to calc register offsets */
bool is_hw_big_endian;
+ unsigned long clock_rate;
struct platform_device *pdev;
const struct mfd_cell *cell;
int irq;
@@ -294,7 +298,7 @@ static u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
return ds1wm_data->read_byte;
}
-static int ds1wm_find_divisor(int gclk)
+static int ds1wm_find_divisor(unsigned long gclk)
{
int i;
@@ -309,17 +313,16 @@ static void ds1wm_up(struct ds1wm_data *ds1wm_data)
{
int divisor;
struct device *dev = &ds1wm_data->pdev->dev;
- struct ds1wm_driver_data *plat = dev_get_platdata(dev);
- if (ds1wm_data->cell->enable)
+ if (ds1wm_data->cell && ds1wm_data->cell->enable)
ds1wm_data->cell->enable(ds1wm_data->pdev);
- divisor = ds1wm_find_divisor(plat->clock_rate);
- dev_dbg(dev, "found divisor 0x%x for clock %d\n",
- divisor, plat->clock_rate);
+ divisor = ds1wm_find_divisor(ds1wm_data->clock_rate);
+ dev_dbg(dev, "found divisor 0x%x for clock %lu\n",
+ divisor, ds1wm_data->clock_rate);
if (divisor == 0) {
- dev_err(dev, "no suitable divisor for %dHz clock\n",
- plat->clock_rate);
+ dev_err(dev, "no suitable divisor for %luHz clock\n",
+ ds1wm_data->clock_rate);
return;
}
ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor);
@@ -338,7 +341,7 @@ static void ds1wm_down(struct ds1wm_data *ds1wm_data)
ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
ds1wm_data->int_en_reg_none);
- if (ds1wm_data->cell->disable)
+ if (ds1wm_data->cell && ds1wm_data->cell->disable)
ds1wm_data->cell->disable(ds1wm_data->pdev);
}
@@ -529,15 +532,86 @@ static int ds1wm_probe(struct platform_device *pdev)
return -ENOMEM;
ds1wm_data->pdev = pdev;
- ds1wm_data->cell = mfd_get_cell(pdev);
- if (!ds1wm_data->cell)
- return -ENODEV;
- plat = dev_get_platdata(&pdev->dev);
- if (!plat)
- return -ENODEV;
+
+ if (pdev->dev.of_node) {
+ /* Using device tree */
+ struct device_node *node = pdev->dev.of_node;
+ uint32_t register_size;
+ uint32_t clock_rate;
+
+ ret = of_property_read_u32(node, "maxim,register-size",
+ ®ister_size);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to read maxim,register-size from dtb\n");
+ return ret;
+ }
+
+ switch (register_size) {
+ case 1:
+ ds1wm_data->bus_shift = 0;
+ break;
+ case 2:
+ ds1wm_data->bus_shift = 1;
+ break;
+ case 4:
+ ds1wm_data->bus_shift = 2;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "Invalid value for maxim,register-size: %u\n",
+ register_size);
+ return -EINVAL;
+ }
+
+ ds1wm_data->is_hw_big_endian = of_property_read_bool(node,
+ "maxim,big-endian");
+
+ if (of_property_read_bool(node, "maxim,active-high"))
+ ds1wm_data->int_en_reg_none = DS1WM_INTEN_IAS;
+ else
+ ds1wm_data->int_en_reg_none = 0;
+
+ ret = of_property_read_u32(node, "maxim,reset-recover-delay",
+ &ds1wm_data->reset_recover_delay);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to read maxim,reset-recover-delay from dtb\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(node, "maxim,clock-rate",
+ &clock_rate);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to read maxim,clock-rate from dtb\n");
+ return ret;
+ }
+ ds1wm_data->clock_rate = clock_rate;
+
+ ds1wm_data->strong_pullup = of_property_read_bool(node,
+ "maxim,strong-pullup");
+ } else {
+ /* Using platform data */
+ ds1wm_data->cell = mfd_get_cell(pdev);
+ if (!ds1wm_data->cell)
+ return -ENODEV;
+ plat = dev_get_platdata(&pdev->dev);
+ if (!plat)
+ return -ENODEV;
+
+ ds1wm_data->bus_shift = plat->bus_shift;
+ ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian;
+
+ ds1wm_data->int_en_reg_none =
+ (plat->active_high ? DS1WM_INTEN_IAS : 0);
+ ds1wm_data->reset_recover_delay = plat->reset_recover_delay;
+
+ ds1wm_data->clock_rate = plat->clock_rate;
+ }
/* how many bits to shift register number to get register offset */
- if (plat->bus_shift > 2) {
+ if (ds1wm_data->bus_shift > 2) {
dev_err(&ds1wm_data->pdev->dev,
"illegal bus shift %d, not written",
ds1wm_data->bus_shift);
@@ -553,14 +627,10 @@ static int ds1wm_probe(struct platform_device *pdev)
return -EINVAL;
}
- ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian;
-
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res)
return -ENXIO;
ds1wm_data->irq = res->start;
- ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0);
- ds1wm_data->reset_recover_delay = plat->reset_recover_delay;
/* Mask interrupts, set IAS before claiming interrupt */
inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN);
@@ -643,9 +713,20 @@ static int ds1wm_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id driver_of_ids[] = {
+ {
+ .compatible = "maxim,ds1wm",
+ },
+ {
+ /* sentinel */
+ }
+};
+
static struct platform_driver ds1wm_driver = {
.driver = {
.name = "ds1wm",
+ .owner = THIS_MODULE,
+ .of_match_table = driver_of_ids,
},
.probe = ds1wm_probe,
.remove = ds1wm_remove,
@@ -667,6 +748,7 @@ static void __exit ds1wm_exit(void)
module_init(ds1wm_init);
module_exit(ds1wm_exit);
+MODULE_DEVICE_TABLE(of, driver_of_ids);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@xxxxxx>, "
"Matt Reimer <mreimer@xxxxxxxx>,"
--
2.25.1