From 9ab05837599e39fa37bc17c0b1725df8bea0972b Mon Sep 17 00:00:00 2001 From: codewalker Date: Wed, 15 Apr 2015 19:48:52 +0900 Subject: [PATCH] ODROIDC: Add 1-Wire driver. Conflicts: arch/arm/boot/dts/meson8b_odroidc.dts Change-Id: I646ca2c20e25218da630ce965a1c43efcde2fbed --- arch/arm/boot/dts/meson8b_odroidc.dts | 8 + arch/arm/configs/odroidc_defconfig | 26 ++- drivers/w1/masters/Makefile | 6 + drivers/w1/masters/w1-gpio-aml.c | 236 ++++++++++++++++++++++++++ drivers/w1/w1_netlink.c | 25 +-- 5 files changed, 288 insertions(+), 13 deletions(-) create mode 100644 drivers/w1/masters/w1-gpio-aml.c diff --git a/arch/arm/boot/dts/meson8b_odroidc.dts b/arch/arm/boot/dts/meson8b_odroidc.dts index 88d9038017ab..454db5999e5c 100755 --- a/arch/arm/boot/dts/meson8b_odroidc.dts +++ b/arch/arm/boot/dts/meson8b_odroidc.dts @@ -944,6 +944,14 @@ dev_name = "pwm-ctrl"; status = "ok"; }; + + w1 { + compatible = "w1-gpio"; + dev_name = "w1"; + status = "ok"; + gpios = "GPIOY_3"; + // linux,open-drain; // .is_open_drain = 1; + }; }; /* end of / */ /* vim: set ts=4 sw=4 tw=80:*/ diff --git a/arch/arm/configs/odroidc_defconfig b/arch/arm/configs/odroidc_defconfig index 8422cfc01058..d3e03bd0f8d5 100755 --- a/arch/arm/configs/odroidc_defconfig +++ b/arch/arm/configs/odroidc_defconfig @@ -2049,7 +2049,31 @@ CONFIG_GPIO_SYSFS=y # # USB GPIO expanders: # -# CONFIG_W1 is not set +CONFIG_W1=m + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS1WM is not set +CONFIG_W1_MASTER_GPIO=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_BQ27000 is not set CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index c5a3e96fcbab..b2e26b4c8f76 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -2,6 +2,12 @@ # Makefile for 1-wire bus master drivers. # +ifeq ($(CONFIG_MACH_MESON8B_ODROIDC),y) + w1-gpio-objs := w1-gpio-aml.o +else + w1-gpio-objs := w1-gpio.o +endif + obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o diff --git a/drivers/w1/masters/w1-gpio-aml.c b/drivers/w1/masters/w1-gpio-aml.c new file mode 100644 index 000000000000..cac78567e7f8 --- /dev/null +++ b/drivers/w1/masters/w1-gpio-aml.c @@ -0,0 +1,236 @@ +/* + * w1-gpio - GPIO w1 bus master driver + * + * Copyright (C) 2007 Ville Syrjala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../w1.h" +#include "../w1_int.h" + +#define MODULE_NAME "amlw1" + +static int w1_gpio_pin = 0; +static int w1_gpio_pullup = 0; + +module_param(w1_gpio_pin,int,0644); +MODULE_PARM_DESC(w1_gpio_pin,"\n odroid gpio number for 1-wire\n"); + +module_param(w1_gpio_pullup,int,0644); +MODULE_PARM_DESC(w1_gpio_pullup,"\n odroid gpio number for 1-wire ext_pullup\n"); + +static void w1_gpio_write_bit_dir(void *data, u8 bit) +{ + struct w1_gpio_platform_data *pdata = data; + + if (bit) + amlogic_gpio_direction_input(pdata->pin, MODULE_NAME); + else + amlogic_gpio_direction_output(pdata->pin, 0, MODULE_NAME); +} + +static void w1_gpio_write_bit_val(void *data, u8 bit) +{ + struct w1_gpio_platform_data *pdata = data; + + amlogic_set_value(pdata->pin, bit, MODULE_NAME); +} + +static u8 w1_gpio_read_bit(void *data) +{ + struct w1_gpio_platform_data *pdata = data; + + return amlogic_get_value(pdata->pin, MODULE_NAME) ? 1 : 0; +} + +#if defined(CONFIG_OF) +static struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); +#endif + +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "linux,open-drain", NULL)) + pdata->is_open_drain = 1; + + if(w1_gpio_pin) + pdata->pin = w1_gpio_pin; + else + pdata->pin = of_get_gpio(np, 0); + + pdata->ext_pullup_enable_pin = w1_gpio_pullup; + pdev->dev.platform_data = pdata; + + return 0; +} + +static int w1_gpio_probe(struct platform_device *pdev) +{ + struct w1_bus_master *master; + struct w1_gpio_platform_data *pdata; + int err; + + if (of_have_populated_dt()) { + err = w1_gpio_probe_dt(pdev); + if (err < 0) { + dev_err(&pdev->dev, "Failed to parse DT\n"); + return err; + } + } + + pdata = pdev->dev.platform_data; + + if (!pdata) { + dev_err(&pdev->dev, "No configuration data\n"); + return -ENXIO; + } + + master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); + if (!master) { + dev_err(&pdev->dev, "Out of memory\n"); + return -ENOMEM; + } + + err = amlogic_gpio_request(pdata->pin, MODULE_NAME); + if (err) { + dev_err(&pdev->dev, "gpio_request (pin) failed\n"); + goto free_master; + } + + if(pdata->ext_pullup_enable_pin) { + err = amlogic_gpio_request_one(pdata->ext_pullup_enable_pin, + GPIOF_INIT_LOW, "w1 pullup"); + if (err < 0) { + dev_err(&pdev->dev, "gpio_request_one " + "(ext_pullup_enable_pin) failed\n"); + goto free_gpio; + } + } + + master->data = pdata; + master->read_bit = w1_gpio_read_bit; + + if (pdata->is_open_drain) { + amlogic_gpio_direction_output(pdata->pin, 1, MODULE_NAME); + master->write_bit = w1_gpio_write_bit_val; + } else { + amlogic_gpio_direction_input(pdata->pin, MODULE_NAME); + master->write_bit = w1_gpio_write_bit_dir; + } + + err = w1_add_master_device(master); + if (err) { + dev_err(&pdev->dev, "w1_add_master device failed\n"); + goto free_gpio_ext_pu; + } + + if (pdata->enable_external_pullup) + pdata->enable_external_pullup(1); + + if(pdata->ext_pullup_enable_pin) + amlogic_set_value(pdata->ext_pullup_enable_pin, 1, MODULE_NAME); + + platform_set_drvdata(pdev, master); + + return 0; + + free_gpio_ext_pu: + if(pdata->ext_pullup_enable_pin) + amlogic_gpio_free(pdata->ext_pullup_enable_pin, MODULE_NAME); + free_gpio: + amlogic_gpio_free(pdata->pin, MODULE_NAME); + free_master: + kfree(master); + + return err; +} + +static int w1_gpio_remove(struct platform_device *pdev) +{ + struct w1_bus_master *master = platform_get_drvdata(pdev); + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + + if (pdata->enable_external_pullup) + pdata->enable_external_pullup(0); + + if(pdata->ext_pullup_enable_pin) + amlogic_set_value(pdata->ext_pullup_enable_pin, 0, MODULE_NAME); + + w1_remove_master_device(master); + amlogic_gpio_free(pdata->pin, MODULE_NAME); + kfree(master); + + return 0; +} + +#ifdef CONFIG_PM + +static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + + if (pdata->enable_external_pullup) + pdata->enable_external_pullup(0); + + return 0; +} + +static int w1_gpio_resume(struct platform_device *pdev) +{ + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + + if (pdata->enable_external_pullup) + pdata->enable_external_pullup(1); + + return 0; +} + +#else +#define w1_gpio_suspend NULL +#define w1_gpio_resume NULL +#endif + +static struct platform_driver w1_gpio_driver = { + .driver = { + .name = "w1-gpio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(w1_gpio_dt_ids), + }, + .probe = w1_gpio_probe, + .remove = w1_gpio_remove, + .suspend = w1_gpio_suspend, + .resume = w1_gpio_resume, +}; + +module_platform_driver(w1_gpio_driver); + +MODULE_DESCRIPTION("GPIO w1 bus master driver for amlogic"); +MODULE_AUTHOR("Ville Syrjala "); +MODULE_LICENSE("GPL"); diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 40788c925d1c..73705aff53cb 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -54,28 +54,29 @@ static void w1_send_slave(struct w1_master *dev, u64 rn) struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); int avail; + u64 *data; /* update kernel slave list */ w1_slave_found(dev, rn); avail = dev->priv_size - cmd->len; - if (avail > 8) { - u64 *data = (void *)(cmd + 1) + cmd->len; + if (avail < 8) { + msg->ack++; + cn_netlink_send(msg, 0, GFP_KERNEL); - *data = rn; - cmd->len += 8; - hdr->len += 8; - msg->len += 8; - return; + msg->len = sizeof(struct w1_netlink_msg) + + sizeof(struct w1_netlink_cmd); + hdr->len = sizeof(struct w1_netlink_cmd); + cmd->len = 0; } - msg->ack++; - cn_netlink_send(msg, 0, GFP_KERNEL); + data = (void *)(cmd + 1) + cmd->len; - msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); - hdr->len = sizeof(struct w1_netlink_cmd); - cmd->len = 0; + *data = rn; + cmd->len += 8; + hdr->len += 8; + msg->len += 8; } static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,