Messages in this thread Patch in this message | | | From | Julian Haller <> | Subject | [PATCH 2/4] w1: ds1wm: Add device tree support | Date | Thu, 30 Jun 2022 13:26:49 +0200 |
| |
From: Julian Haller <julian.haller@philips.com>
The ds1wm driver now supports both, initialization with platform_data and initialization via device tree.
Signed-off-by: Julian Haller <julian.haller@philips.com> --- 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@tlt.hu>, " "Matt Reimer <mreimer@vpop.net>," -- 2.25.1
| |