1ad8dc96eSVille Syrjala /* 2ad8dc96eSVille Syrjala * w1-gpio - GPIO w1 bus master driver 3ad8dc96eSVille Syrjala * 4ad8dc96eSVille Syrjala * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> 5ad8dc96eSVille Syrjala * 6ad8dc96eSVille Syrjala * This program is free software; you can redistribute it and/or modify 7ad8dc96eSVille Syrjala * it under the terms of the GNU General Public License version 2 8ad8dc96eSVille Syrjala * as published by the Free Software Foundation. 9ad8dc96eSVille Syrjala */ 10ad8dc96eSVille Syrjala 11ad8dc96eSVille Syrjala #include <linux/init.h> 12ad8dc96eSVille Syrjala #include <linux/module.h> 13ad8dc96eSVille Syrjala #include <linux/platform_device.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 15ad8dc96eSVille Syrjala #include <linux/w1-gpio.h> 16*e0fc62a6SLinus Walleij #include <linux/gpio/consumer.h> 175f3d1382SDaniel Mack #include <linux/of_platform.h> 18277ed0d5SPantelis Antoniou #include <linux/err.h> 198a1861d9SPantelis Antoniou #include <linux/of.h> 203089a4c8SEvgeny Boger #include <linux/delay.h> 21ad8dc96eSVille Syrjala 22de0d6dbdSAndrew F. Davis #include <linux/w1.h> 23ad8dc96eSVille Syrjala 243089a4c8SEvgeny Boger static u8 w1_gpio_set_pullup(void *data, int delay) 253089a4c8SEvgeny Boger { 263089a4c8SEvgeny Boger struct w1_gpio_platform_data *pdata = data; 273089a4c8SEvgeny Boger 283089a4c8SEvgeny Boger if (delay) { 293089a4c8SEvgeny Boger pdata->pullup_duration = delay; 303089a4c8SEvgeny Boger } else { 313089a4c8SEvgeny Boger if (pdata->pullup_duration) { 32*e0fc62a6SLinus Walleij /* 33*e0fc62a6SLinus Walleij * This will OVERRIDE open drain emulation and force-pull 34*e0fc62a6SLinus Walleij * the line high for some time. 35*e0fc62a6SLinus Walleij */ 36*e0fc62a6SLinus Walleij gpiod_set_raw_value(pdata->gpiod, 1); 373089a4c8SEvgeny Boger msleep(pdata->pullup_duration); 38*e0fc62a6SLinus Walleij /* 39*e0fc62a6SLinus Walleij * This will simply set the line as input since we are doing 40*e0fc62a6SLinus Walleij * open drain emulation in the GPIO library. 41*e0fc62a6SLinus Walleij */ 42*e0fc62a6SLinus Walleij gpiod_set_value(pdata->gpiod, 1); 433089a4c8SEvgeny Boger } 443089a4c8SEvgeny Boger pdata->pullup_duration = 0; 453089a4c8SEvgeny Boger } 463089a4c8SEvgeny Boger 473089a4c8SEvgeny Boger return 0; 483089a4c8SEvgeny Boger } 493089a4c8SEvgeny Boger 50*e0fc62a6SLinus Walleij static void w1_gpio_write_bit(void *data, u8 bit) 51ad8dc96eSVille Syrjala { 52ad8dc96eSVille Syrjala struct w1_gpio_platform_data *pdata = data; 53ad8dc96eSVille Syrjala 54*e0fc62a6SLinus Walleij gpiod_set_value(pdata->gpiod, bit); 55ad8dc96eSVille Syrjala } 56ad8dc96eSVille Syrjala 57ad8dc96eSVille Syrjala static u8 w1_gpio_read_bit(void *data) 58ad8dc96eSVille Syrjala { 59ad8dc96eSVille Syrjala struct w1_gpio_platform_data *pdata = data; 60ad8dc96eSVille Syrjala 61*e0fc62a6SLinus Walleij return gpiod_get_value(pdata->gpiod) ? 1 : 0; 62ad8dc96eSVille Syrjala } 63ad8dc96eSVille Syrjala 6434ccd873SJohan Hovold #if defined(CONFIG_OF) 650a56c0e1SFabian Frederick static const struct of_device_id w1_gpio_dt_ids[] = { 665f3d1382SDaniel Mack { .compatible = "w1-gpio" }, 675f3d1382SDaniel Mack {} 685f3d1382SDaniel Mack }; 695f3d1382SDaniel Mack MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); 7034ccd873SJohan Hovold #endif 715f3d1382SDaniel Mack 7206a8f1feSHauke Mehrtens static int w1_gpio_probe(struct platform_device *pdev) 73ad8dc96eSVille Syrjala { 74ad8dc96eSVille Syrjala struct w1_bus_master *master; 755f3d1382SDaniel Mack struct w1_gpio_platform_data *pdata; 76*e0fc62a6SLinus Walleij struct device *dev = &pdev->dev; 77*e0fc62a6SLinus Walleij struct device_node *np = dev->of_node; 78*e0fc62a6SLinus Walleij /* Enforce open drain mode by default */ 79*e0fc62a6SLinus Walleij enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; 80ad8dc96eSVille Syrjala int err; 81ad8dc96eSVille Syrjala 828a1861d9SPantelis Antoniou if (of_have_populated_dt()) { 83*e0fc62a6SLinus Walleij pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 84*e0fc62a6SLinus Walleij if (!pdata) 85*e0fc62a6SLinus Walleij return -ENOMEM; 865f3d1382SDaniel Mack 87*e0fc62a6SLinus Walleij /* 88*e0fc62a6SLinus Walleij * This parameter means that something else than the gpiolib has 89*e0fc62a6SLinus Walleij * already set the line into open drain mode, so we should just 90*e0fc62a6SLinus Walleij * driver it high/low like we are in full control of the line and 91*e0fc62a6SLinus Walleij * open drain will happen transparently. 92*e0fc62a6SLinus Walleij */ 93*e0fc62a6SLinus Walleij if (of_get_property(np, "linux,open-drain", NULL)) 94*e0fc62a6SLinus Walleij gflags = GPIOD_OUT_LOW; 95*e0fc62a6SLinus Walleij 96*e0fc62a6SLinus Walleij pdev->dev.platform_data = pdata; 97*e0fc62a6SLinus Walleij } 98*e0fc62a6SLinus Walleij pdata = dev_get_platdata(dev); 995f3d1382SDaniel Mack 1008a1861d9SPantelis Antoniou if (!pdata) { 101*e0fc62a6SLinus Walleij dev_err(dev, "No configuration data\n"); 102ad8dc96eSVille Syrjala return -ENXIO; 1038a1861d9SPantelis Antoniou } 104ad8dc96eSVille Syrjala 105*e0fc62a6SLinus Walleij master = devm_kzalloc(dev, sizeof(struct w1_bus_master), 106d27f25c9SMarkus Pargmann GFP_KERNEL); 1078a1861d9SPantelis Antoniou if (!master) { 108*e0fc62a6SLinus Walleij dev_err(dev, "Out of memory\n"); 109ad8dc96eSVille Syrjala return -ENOMEM; 1108a1861d9SPantelis Antoniou } 111ad8dc96eSVille Syrjala 112*e0fc62a6SLinus Walleij pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); 113*e0fc62a6SLinus Walleij if (IS_ERR(pdata->gpiod)) { 114*e0fc62a6SLinus Walleij dev_err(dev, "gpio_request (pin) failed\n"); 115*e0fc62a6SLinus Walleij return PTR_ERR(pdata->gpiod); 1168a1861d9SPantelis Antoniou } 117ad8dc96eSVille Syrjala 118*e0fc62a6SLinus Walleij pdata->pullup_gpiod = 119*e0fc62a6SLinus Walleij devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW); 120*e0fc62a6SLinus Walleij if (IS_ERR(pdata->pullup_gpiod)) { 121*e0fc62a6SLinus Walleij dev_err(dev, "gpio_request_one " 1228a1861d9SPantelis Antoniou "(ext_pullup_enable_pin) failed\n"); 123*e0fc62a6SLinus Walleij return PTR_ERR(pdata->pullup_gpiod); 1248a1861d9SPantelis Antoniou } 125d2323cf7SDaniel Mack 126ad8dc96eSVille Syrjala master->data = pdata; 127ad8dc96eSVille Syrjala master->read_bit = w1_gpio_read_bit; 128*e0fc62a6SLinus Walleij gpiod_direction_output(pdata->gpiod, 1); 129*e0fc62a6SLinus Walleij master->write_bit = w1_gpio_write_bit; 130ad8dc96eSVille Syrjala 131*e0fc62a6SLinus Walleij /* 132*e0fc62a6SLinus Walleij * If we are using open drain emulation from the GPIO library, 133*e0fc62a6SLinus Walleij * we need to use this pullup function that hammers the line 134*e0fc62a6SLinus Walleij * high using a raw accessor to provide pull-up for the w1 135*e0fc62a6SLinus Walleij * line. 136*e0fc62a6SLinus Walleij */ 137*e0fc62a6SLinus Walleij if (gflags == GPIOD_OUT_LOW_OPEN_DRAIN) 1383089a4c8SEvgeny Boger master->set_pullup = w1_gpio_set_pullup; 139ad8dc96eSVille Syrjala 140ad8dc96eSVille Syrjala err = w1_add_master_device(master); 1418a1861d9SPantelis Antoniou if (err) { 142*e0fc62a6SLinus Walleij dev_err(dev, "w1_add_master device failed\n"); 143d27f25c9SMarkus Pargmann return err; 1448a1861d9SPantelis Antoniou } 145ad8dc96eSVille Syrjala 146c8a06c1eSDaniel Mack if (pdata->enable_external_pullup) 147c8a06c1eSDaniel Mack pdata->enable_external_pullup(1); 148c8a06c1eSDaniel Mack 149*e0fc62a6SLinus Walleij if (pdata->pullup_gpiod) 150*e0fc62a6SLinus Walleij gpiod_set_value(pdata->pullup_gpiod, 1); 151d2323cf7SDaniel Mack 152ad8dc96eSVille Syrjala platform_set_drvdata(pdev, master); 153ad8dc96eSVille Syrjala 154ad8dc96eSVille Syrjala return 0; 155ad8dc96eSVille Syrjala } 156ad8dc96eSVille Syrjala 15701230551SJohan Hovold static int w1_gpio_remove(struct platform_device *pdev) 158ad8dc96eSVille Syrjala { 159ad8dc96eSVille Syrjala struct w1_bus_master *master = platform_get_drvdata(pdev); 160c853b167SJingoo Han struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); 161ad8dc96eSVille Syrjala 162c8a06c1eSDaniel Mack if (pdata->enable_external_pullup) 163c8a06c1eSDaniel Mack pdata->enable_external_pullup(0); 164c8a06c1eSDaniel Mack 165*e0fc62a6SLinus Walleij if (pdata->pullup_gpiod) 166*e0fc62a6SLinus Walleij gpiod_set_value(pdata->pullup_gpiod, 0); 167d2323cf7SDaniel Mack 168ad8dc96eSVille Syrjala w1_remove_master_device(master); 169ad8dc96eSVille Syrjala 170ad8dc96eSVille Syrjala return 0; 171ad8dc96eSVille Syrjala } 172ad8dc96eSVille Syrjala 17336fccce0SDmitry Torokhov static int __maybe_unused w1_gpio_suspend(struct device *dev) 174c8a06c1eSDaniel Mack { 17536fccce0SDmitry Torokhov struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); 176c8a06c1eSDaniel Mack 177c8a06c1eSDaniel Mack if (pdata->enable_external_pullup) 178c8a06c1eSDaniel Mack pdata->enable_external_pullup(0); 179c8a06c1eSDaniel Mack 180c8a06c1eSDaniel Mack return 0; 181c8a06c1eSDaniel Mack } 182c8a06c1eSDaniel Mack 18336fccce0SDmitry Torokhov static int __maybe_unused w1_gpio_resume(struct device *dev) 184c8a06c1eSDaniel Mack { 18536fccce0SDmitry Torokhov struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); 186c8a06c1eSDaniel Mack 187c8a06c1eSDaniel Mack if (pdata->enable_external_pullup) 188c8a06c1eSDaniel Mack pdata->enable_external_pullup(1); 189c8a06c1eSDaniel Mack 190c8a06c1eSDaniel Mack return 0; 191c8a06c1eSDaniel Mack } 192c8a06c1eSDaniel Mack 19336fccce0SDmitry Torokhov static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume); 194c8a06c1eSDaniel Mack 195ad8dc96eSVille Syrjala static struct platform_driver w1_gpio_driver = { 196ad8dc96eSVille Syrjala .driver = { 197ad8dc96eSVille Syrjala .name = "w1-gpio", 19836fccce0SDmitry Torokhov .pm = &w1_gpio_pm_ops, 1995f3d1382SDaniel Mack .of_match_table = of_match_ptr(w1_gpio_dt_ids), 200ad8dc96eSVille Syrjala }, 2018a1861d9SPantelis Antoniou .probe = w1_gpio_probe, 20201230551SJohan Hovold .remove = w1_gpio_remove, 203ad8dc96eSVille Syrjala }; 204ad8dc96eSVille Syrjala 2058a1861d9SPantelis Antoniou module_platform_driver(w1_gpio_driver); 206ad8dc96eSVille Syrjala 207ad8dc96eSVille Syrjala MODULE_DESCRIPTION("GPIO w1 bus master driver"); 208ad8dc96eSVille Syrjala MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); 209ad8dc96eSVille Syrjala MODULE_LICENSE("GPL"); 210