From 1d9c5ae2a9968e34dcb1f4849a0868c703111537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Mon, 13 Nov 2017 11:59:30 +0100 Subject: [PATCH] eeprom: at24: Simplify WP management and make it optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The WP management introduced by Amlogic was uselessly complicated. It was also silently mandatory, which caused the following error without a WP-control GPIO: [ 1.972520@0] faild to get write interval time ! [ 1.977044@0] faild to get write interval time ! [ 1.981698@0] ------------[ cut here ]------------ [ 1.986505@0] WARNING: CPU: 0 PID: 1 at /home/terry/project/vim/nougat/common/drivers/gpio/gpiolib.c:159 gpio_to_desc+0x58/0x60() [ 1.998257@0] invalid GPIO -1514520 [ 2.001731@0] Modules linked in: [ 2.004961@0] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.14.29-g576a041-dirty #14 [ 2.012575@0] Call trace: [ 2.015201@0] [] dump_backtrace+0x0/0x140 [ 2.020830@0] [] show_stack+0x20/0x2c [ 2.026046@0] [] dump_stack+0x74/0xc0 [ 2.031302@0] [] warn_slowpath_common+0x90/0xb8 [ 2.037438@0] [] warn_slowpath_fmt+0x74/0x88 [ 2.043290@0] [] gpio_to_desc+0x54/0x60 [ 2.048706@0] [] gpio_request+0x20/0x38 [ 2.054157@0] [] at24_wp_enable+0x30/0x78 [ 2.059731@0] [] at24_dt_parse+0x9c/0x110 [ 2.065338@0] [] at24_probe+0x314/0x584 [ 2.070782@0] [] i2c_device_probe+0xa0/0xe4 [ 2.076533@0] [] really_probe+0x74/0x240 [ 2.082051@0] [] __driver_attach+0xb0/0xb8 [ 2.087749@0] [] bus_for_each_dev+0x68/0xac [ 2.093513@0] [] driver_attach+0x2c/0x38 [ 2.099019@0] [] bus_add_driver+0x158/0x210 [ 2.104818@0] [] driver_register+0x6c/0x138 [ 2.110575@0] [] i2c_register_driver+0x3c/0xc0 [ 2.116609@0] [] at24_init+0x50/0x5c [ 2.121792@0] [] do_one_initcall+0xe0/0x12c [ 2.127546@0] [] kernel_init_freeable+0x134/0x1d8 [ 2.133851@0] [] kernel_init+0x1c/0xdc [ 2.139213@0] ---[ end trace c84d7b19dc3d49e2 ]--- [ 2.144000@0] gpiod_request: invalid GPIO [ 2.148017@0] faild to alloc write protect (-1514520)! [ 2.153185@0] EEPROM_AT24c256 [ 2.156086@0] write protect port level is -1514520[ 2.160888@0] wp_port=-1514520 write_ops_interval=-64ms [ 2.166151@0] at24 2-0050: 32768 byte 24c256 EEPROM, writable, 64 bytes/write Signed-off-by: Benoît Thébaudeau --- arch/arm64/boot/dts/amlogic/gxtvbb_p301.dts | 1 - drivers/misc/eeprom/at24.c | 134 +++++++------------- include/linux/platform_data/at24.h | 10 +- 3 files changed, 51 insertions(+), 94 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/gxtvbb_p301.dts b/arch/arm64/boot/dts/amlogic/gxtvbb_p301.dts index bbfafda1cdf3c..b7e0022a6e3ff 100644 --- a/arch/arm64/boot/dts/amlogic/gxtvbb_p301.dts +++ b/arch/arm64/boot/dts/amlogic/gxtvbb_p301.dts @@ -1760,7 +1760,6 @@ pagesize = <8>; write_ops_interval= <10>;/*Write operation interval at24c32 at24c64 is 10ms at24c128 is 5ms in spec*/ wp_gpios = <&gpio GPIOY_7 GPIO_ACTIVE_HIGH>; - write_gpio_port_status = <0>; }; }; &pinmux { diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 3230c5b7698e9..0889f1098b4a5 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -24,11 +24,9 @@ #include #include #include -#include -#include #include #include - +#include /* * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. @@ -135,28 +133,23 @@ static const struct i2c_device_id at24_ids[] = { { /* END OF LIST */ } }; MODULE_DEVICE_TABLE(i2c, at24_ids); -#define MODULE_NAME "at24" + static struct at24_data *gp_at24; static ssize_t at24_wp_show(struct class *class, struct class_attribute *attr, char *buf) { - - return sprintf(buf, "%d\n", gpiod_get_value(gp_at24->chip.wp_pin_desc)); + return sprintf(buf, "%d\n", gpio_get_value(gp_at24->chip.wp_port)); } static ssize_t at24_wp_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { u8 wp; - u8 ret; - ret = sscanf(buf, "%x", (int *)&wp); + u8 ret; + ret = sscanf(buf, "%hhx", &wp); mutex_lock(&gp_at24->lock); - if (wp == 0) - amlogic_gpio_direction_output(gp_at24->chip.wp_port , 0 , - MODULE_NAME); - else if (wp == 1) - amlogic_gpio_direction_output(gp_at24->chip.wp_port , 1 , - MODULE_NAME); + if (wp <= 1) + gpio_set_value(gp_at24->chip.wp_port, wp); else pr_info("only support 1 or 0\n"); @@ -168,39 +161,14 @@ struct class *at24_class; static CLASS_ATTR(at24_wp , S_IWUSR | S_IRUGO , at24_wp_show , at24_wp_store); -/*eeprom protect gpio enable*/ -void at24_wp_enable(struct at24_platform_data *chip) -{ - int ret; - if (chip->wp_port > 0) { - ret = gpio_request(chip->wp_port , MODULE_NAME); - if (ret) - pr_info("faild to alloc write protect (%d)!\n" , - chip->wp_port); - else - amlogic_gpio_direction_output(chip->wp_port , - chip->wp_port_level , MODULE_NAME); - } else { - pr_info("wrong wp port\n"); - } -} /* enable write protect*/ -void at24_enable_write_operation(struct at24_platform_data *chip) +static void at24_enable_write_operation(struct at24_platform_data *chip, + bool enable) { -if (chip->wp_port > 0) { - chip->wp_port_level = chip->wp_port_level_save; - amlogic_gpio_direction_output(chip->wp_port , - chip->wp_port_level , MODULE_NAME); - } -} -/* disable write protect*/ -void at24_disable_write_operation(struct at24_platform_data *chip) -{ -if (chip->wp_port > 0) { - chip->wp_port_level = !chip->wp_port_level_save; - amlogic_gpio_direction_output(chip->wp_port , - chip->wp_port_level , MODULE_NAME); - } + if (gpio_is_valid(chip->wp_port)) + gpio_set_value(chip->wp_port, + enable ? !chip->wp_port_active_level : + chip->wp_port_active_level); } /*-------------------------------------------------------------------------*/ @@ -469,7 +437,7 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off, if (unlikely(!count)) return count; /*enable write ops*/ - at24_enable_write_operation(&at24->chip); + at24_enable_write_operation(&at24->chip, true); mdelay(at24->chip.write_ops_interval); /* * Write data to chip, protecting against concurrent updates @@ -496,7 +464,7 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off, mutex_unlock(&at24->lock); /*write protect*/ - at24_disable_write_operation(&at24->chip); + at24_enable_write_operation(&at24->chip, false); return retval; } @@ -561,43 +529,33 @@ static void at24_get_ofdata(struct i2c_client *client, { } #endif /* CONFIG_OF */ -void at24_dt_parse(struct i2c_client *client , struct at24_platform_data *chip) +static int at24_dt_parse(struct i2c_client *client, + struct at24_platform_data *chip) { -/* const char *str;*/ - int ret; - enum of_gpio_flags flags; - struct device_node *node = client->dev.of_node; + enum of_gpio_flags flags; + int ret; - ret = of_property_read_u32(node, "write_ops_interval", - &(chip->write_ops_interval)); - if (ret) - pr_info("faild to get write interval time !\n"); - - chip->wp_pin_desc = of_get_named_gpiod_flags(node , "wp_gpios" , - 0 , &flags); - chip->wp_port = desc_to_gpio(chip->wp_pin_desc); - - ret = of_property_read_u32(node , "write_gpio_port_status", - &(chip->wp_port_level)); - if (ret) - pr_info("faild to get write interval time !\n"); - - if (!chip->wp_port_level) - chip->wp_port_level_save = chip->wp_port_level = 0; - /*at24_wp_enable(chip);*/ - else - chip->wp_port_level_save = chip->wp_port_level = 1; - /*at24_wp_enable(chip);*/ - - chip->wp_port_level = !chip->wp_port_level_save; - at24_wp_enable(chip); + chip->write_ops_interval = 0; + of_property_read_u32(node, "write_ops_interval", + &chip->write_ops_interval); + + chip->wp_port = of_get_named_gpio_flags(node, "wp_gpios", 0, &flags); + if (gpio_is_valid(chip->wp_port)) { + chip->wp_port_active_level = !(flags & OF_GPIO_ACTIVE_LOW); + + ret = gpio_request_one(chip->wp_port, + chip->wp_port_active_level ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, + dev_name(&client->dev)); + if (ret) { + dev_err(&client->dev, "unable to request WP GPIO %d\n", + chip->wp_port); + return ret; + } + } - pr_info("EEPROM_AT%s " , client->name); - pr_info("write protect port level is %d" , chip->wp_port); - pr_info("wp_port=%d write_ops_interval=%dms\n" , - chip->wp_port , - chip->write_ops_interval); + return 0; } @@ -696,8 +654,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { + err = at24_dt_parse(client, &at24->chip); + if (err) + return err; - at24_dt_parse(client , &at24->chip); if (!use_smbus || i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { @@ -758,10 +718,12 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) /* export data to kernel code */ if (chip.setup) chip.setup(&at24->macc, chip.context); - at24_class = class_create(THIS_MODULE , "at24_wp"); - err = class_create_file(at24_class , &class_attr_at24_wp); + if (writable && gpio_is_valid(chip.wp_port)) { + at24_class = class_create(THIS_MODULE , "at24_wp"); + err = class_create_file(at24_class , &class_attr_at24_wp); + } - return 0; + return err; err_clients: for (i = 1; i < num_addresses; i++) @@ -782,7 +744,9 @@ static int at24_remove(struct i2c_client *client) for (i = 1; i < at24->num_addresses; i++) i2c_unregister_device(at24->client[i]); - class_destroy(at24_class); + if (!(at24->chip.flags & AT24_FLAG_READONLY) && + gpio_is_valid(at24->chip.wp_port)) + class_destroy(at24_class); return 0; } diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h index 6b413513f4d52..8a4c9a73cdf39 100644 --- a/include/linux/platform_data/at24.h +++ b/include/linux/platform_data/at24.h @@ -47,17 +47,11 @@ struct at24_platform_data { #define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ #define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ #define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ - unsigned int wp_port; - unsigned int wp_port_level; - unsigned int wp_port_level_save; + int wp_port; + unsigned int wp_port_active_level; unsigned int write_ops_interval; - struct gpio_desc *wp_pin_desc; void (*setup)(struct memory_accessor *, void *context); void *context; }; -extern int amlogic_gpio_name_map_num(const char *name); -extern int amlogic_gpio_direction_output(unsigned int pin, int value, - const char *owner); -extern int amlogic_gpio_request(unsigned int pin, const char *label); #endif /* _LINUX_AT24_H */