.. | .. |
---|
1 | | -// SPDX-License-Identifier: GPL-2.0+ |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
2 | 2 | /* |
---|
3 | 3 | * at24.c - handle most I2C EEPROMs |
---|
4 | 4 | * |
---|
.. | .. |
---|
6 | 6 | * Copyright (C) 2008 Wolfram Sang, Pengutronix |
---|
7 | 7 | */ |
---|
8 | 8 | |
---|
9 | | -#define DEBUG |
---|
10 | | -#include <linux/kernel.h> |
---|
11 | | -#include <linux/init.h> |
---|
12 | | -#include <linux/module.h> |
---|
13 | | -#include <linux/of_device.h> |
---|
14 | | -#include <linux/slab.h> |
---|
15 | | -#include <linux/delay.h> |
---|
16 | | -#include <linux/mutex.h> |
---|
17 | | -#include <linux/mod_devicetable.h> |
---|
18 | | -#include <linux/log2.h> |
---|
19 | | -#include <linux/bitops.h> |
---|
20 | | -#include <linux/jiffies.h> |
---|
21 | | -#include <linux/property.h> |
---|
22 | 9 | #include <linux/acpi.h> |
---|
| 10 | +#include <linux/bitops.h> |
---|
| 11 | +#include <linux/capability.h> |
---|
| 12 | +#include <linux/delay.h> |
---|
23 | 13 | #include <linux/i2c.h> |
---|
| 14 | +#include <linux/init.h> |
---|
| 15 | +#include <linux/jiffies.h> |
---|
| 16 | +#include <linux/kernel.h> |
---|
| 17 | +#include <linux/mod_devicetable.h> |
---|
| 18 | +#include <linux/module.h> |
---|
| 19 | +#include <linux/mutex.h> |
---|
24 | 20 | #include <linux/nvmem-provider.h> |
---|
25 | | -#include <linux/regmap.h> |
---|
26 | | -#include <linux/platform_data/at24.h> |
---|
| 21 | +#include <linux/of_device.h> |
---|
27 | 22 | #include <linux/pm_runtime.h> |
---|
28 | | -#include <linux/gpio/consumer.h> |
---|
| 23 | +#include <linux/property.h> |
---|
| 24 | +#include <linux/regmap.h> |
---|
| 25 | +#include <linux/regulator/consumer.h> |
---|
| 26 | +#include <linux/slab.h> |
---|
| 27 | + |
---|
| 28 | +/* Address pointer is 16 bit. */ |
---|
| 29 | +#define AT24_FLAG_ADDR16 BIT(7) |
---|
| 30 | +/* sysfs-entry will be read-only. */ |
---|
| 31 | +#define AT24_FLAG_READONLY BIT(6) |
---|
| 32 | +/* sysfs-entry will be world-readable. */ |
---|
| 33 | +#define AT24_FLAG_IRUGO BIT(5) |
---|
| 34 | +/* Take always 8 addresses (24c00). */ |
---|
| 35 | +#define AT24_FLAG_TAKE8ADDR BIT(4) |
---|
| 36 | +/* Factory-programmed serial number. */ |
---|
| 37 | +#define AT24_FLAG_SERIAL BIT(3) |
---|
| 38 | +/* Factory-programmed mac address. */ |
---|
| 39 | +#define AT24_FLAG_MAC BIT(2) |
---|
| 40 | +/* Does not auto-rollover reads to the next slave address. */ |
---|
| 41 | +#define AT24_FLAG_NO_RDROL BIT(1) |
---|
29 | 42 | |
---|
30 | 43 | /* |
---|
31 | 44 | * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. |
---|
.. | .. |
---|
76 | 89 | u8 flags; |
---|
77 | 90 | |
---|
78 | 91 | struct nvmem_device *nvmem; |
---|
79 | | - |
---|
80 | | - struct gpio_desc *wp_gpio; |
---|
| 92 | + struct regulator *vcc_reg; |
---|
| 93 | + void (*read_post)(unsigned int off, char *buf, size_t count); |
---|
81 | 94 | |
---|
82 | 95 | /* |
---|
83 | 96 | * Some chips tie up multiple I2C addresses; dummy devices reserve |
---|
.. | .. |
---|
107 | 120 | module_param_named(write_timeout, at24_write_timeout, uint, 0); |
---|
108 | 121 | MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); |
---|
109 | 122 | |
---|
110 | | -//Ben |
---|
111 | 123 | struct at24_data *at24_private=NULL; |
---|
| 124 | + |
---|
112 | 125 | struct at24_chip_data { |
---|
113 | | - /* |
---|
114 | | - * these fields mirror their equivalents in |
---|
115 | | - * struct at24_platform_data |
---|
116 | | - */ |
---|
117 | 126 | u32 byte_len; |
---|
118 | 127 | u8 flags; |
---|
| 128 | + void (*read_post)(unsigned int off, char *buf, size_t count); |
---|
119 | 129 | }; |
---|
120 | 130 | |
---|
121 | 131 | #define AT24_CHIP_DATA(_name, _len, _flags) \ |
---|
122 | 132 | static const struct at24_chip_data _name = { \ |
---|
123 | 133 | .byte_len = _len, .flags = _flags, \ |
---|
124 | 134 | } |
---|
| 135 | + |
---|
| 136 | +#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \ |
---|
| 137 | + static const struct at24_chip_data _name = { \ |
---|
| 138 | + .byte_len = _len, .flags = _flags, \ |
---|
| 139 | + .read_post = _read_post, \ |
---|
| 140 | + } |
---|
| 141 | + |
---|
| 142 | +static void at24_read_post_vaio(unsigned int off, char *buf, size_t count) |
---|
| 143 | +{ |
---|
| 144 | + int i; |
---|
| 145 | + |
---|
| 146 | + if (capable(CAP_SYS_ADMIN)) |
---|
| 147 | + return; |
---|
| 148 | + |
---|
| 149 | + /* |
---|
| 150 | + * Hide VAIO private settings to regular users: |
---|
| 151 | + * - BIOS passwords: bytes 0x00 to 0x0f |
---|
| 152 | + * - UUID: bytes 0x10 to 0x1f |
---|
| 153 | + * - Serial number: 0xc0 to 0xdf |
---|
| 154 | + */ |
---|
| 155 | + for (i = 0; i < count; i++) { |
---|
| 156 | + if ((off + i <= 0x1f) || |
---|
| 157 | + (off + i >= 0xc0 && off + i <= 0xdf)) |
---|
| 158 | + buf[i] = 0; |
---|
| 159 | + } |
---|
| 160 | +} |
---|
125 | 161 | |
---|
126 | 162 | /* needs 8 addresses as A0-A2 are ignored */ |
---|
127 | 163 | AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR); |
---|
.. | .. |
---|
139 | 175 | /* spd is a 24c02 in memory DIMMs */ |
---|
140 | 176 | AT24_CHIP_DATA(at24_data_spd, 2048 / 8, |
---|
141 | 177 | AT24_FLAG_READONLY | AT24_FLAG_IRUGO); |
---|
| 178 | +/* 24c02_vaio is a 24c02 on some Sony laptops */ |
---|
| 179 | +AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8, |
---|
| 180 | + AT24_FLAG_READONLY | AT24_FLAG_IRUGO, |
---|
| 181 | + at24_read_post_vaio); |
---|
142 | 182 | AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0); |
---|
143 | 183 | AT24_CHIP_DATA(at24_data_24cs04, 16, |
---|
144 | 184 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); |
---|
.. | .. |
---|
172 | 212 | { "24mac402", (kernel_ulong_t)&at24_data_24mac402 }, |
---|
173 | 213 | { "24mac602", (kernel_ulong_t)&at24_data_24mac602 }, |
---|
174 | 214 | { "spd", (kernel_ulong_t)&at24_data_spd }, |
---|
| 215 | + { "24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio }, |
---|
175 | 216 | { "24c04", (kernel_ulong_t)&at24_data_24c04 }, |
---|
176 | 217 | { "24cs04", (kernel_ulong_t)&at24_data_24cs04 }, |
---|
177 | 218 | { "24c08", (kernel_ulong_t)&at24_data_24c08 }, |
---|
.. | .. |
---|
220 | 261 | }; |
---|
221 | 262 | MODULE_DEVICE_TABLE(of, at24_of_match); |
---|
222 | 263 | |
---|
223 | | -static const struct acpi_device_id at24_acpi_ids[] = { |
---|
| 264 | +static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = { |
---|
224 | 265 | { "INT3499", (kernel_ulong_t)&at24_data_INT3499 }, |
---|
| 266 | + { "TPF0001", (kernel_ulong_t)&at24_data_24c1024 }, |
---|
225 | 267 | { /* END OF LIST */ } |
---|
226 | 268 | }; |
---|
227 | 269 | MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); |
---|
.. | .. |
---|
382 | 424 | struct at24_data *at24; |
---|
383 | 425 | struct device *dev; |
---|
384 | 426 | char *buf = val; |
---|
385 | | - int ret; |
---|
| 427 | + int i, ret; |
---|
386 | 428 | |
---|
387 | 429 | at24 = priv; |
---|
388 | 430 | dev = at24_base_client_dev(at24); |
---|
.. | .. |
---|
405 | 447 | */ |
---|
406 | 448 | mutex_lock(&at24->lock); |
---|
407 | 449 | |
---|
408 | | - while (count) { |
---|
409 | | - ret = at24_regmap_read(at24, buf, off, count); |
---|
| 450 | + for (i = 0; count; i += ret, count -= ret) { |
---|
| 451 | + ret = at24_regmap_read(at24, buf + i, off + i, count); |
---|
410 | 452 | if (ret < 0) { |
---|
411 | 453 | mutex_unlock(&at24->lock); |
---|
412 | 454 | pm_runtime_put(dev); |
---|
413 | 455 | return ret; |
---|
414 | 456 | } |
---|
415 | | - buf += ret; |
---|
416 | | - off += ret; |
---|
417 | | - count -= ret; |
---|
418 | 457 | } |
---|
419 | 458 | |
---|
420 | 459 | mutex_unlock(&at24->lock); |
---|
421 | 460 | |
---|
422 | 461 | pm_runtime_put(dev); |
---|
423 | 462 | |
---|
| 463 | + if (unlikely(at24->read_post)) |
---|
| 464 | + at24->read_post(off, buf, i); |
---|
| 465 | + |
---|
424 | 466 | return 0; |
---|
425 | 467 | } |
---|
426 | 468 | |
---|
427 | | -//add ben |
---|
| 469 | + |
---|
| 470 | + |
---|
428 | 471 | static ssize_t at24_read_private(struct at24_data *at24, |
---|
429 | 472 | char *buf, loff_t off, size_t count) |
---|
430 | 473 | { |
---|
.. | .. |
---|
591 | 634 | * from this host, but not from other I2C masters. |
---|
592 | 635 | */ |
---|
593 | 636 | mutex_lock(&at24->lock); |
---|
594 | | - gpiod_set_value_cansleep(at24->wp_gpio, 0); |
---|
595 | 637 | |
---|
596 | 638 | while (count) { |
---|
597 | 639 | ret = at24_regmap_write(at24, buf, off, count); |
---|
598 | 640 | if (ret < 0) { |
---|
599 | | - gpiod_set_value_cansleep(at24->wp_gpio, 1); |
---|
600 | 641 | mutex_unlock(&at24->lock); |
---|
601 | 642 | pm_runtime_put(dev); |
---|
602 | 643 | return ret; |
---|
.. | .. |
---|
606 | 647 | count -= ret; |
---|
607 | 648 | } |
---|
608 | 649 | |
---|
609 | | - gpiod_set_value_cansleep(at24->wp_gpio, 1); |
---|
610 | 650 | mutex_unlock(&at24->lock); |
---|
611 | 651 | |
---|
612 | 652 | pm_runtime_put(dev); |
---|
.. | .. |
---|
614 | 654 | return 0; |
---|
615 | 655 | } |
---|
616 | 656 | |
---|
617 | | -static void at24_properties_to_pdata(struct device *dev, |
---|
618 | | - struct at24_platform_data *chip) |
---|
619 | | -{ |
---|
620 | | - int err; |
---|
621 | | - u32 val; |
---|
622 | | - |
---|
623 | | - if (device_property_present(dev, "read-only")) |
---|
624 | | - chip->flags |= AT24_FLAG_READONLY; |
---|
625 | | - if (device_property_present(dev, "no-read-rollover")) |
---|
626 | | - chip->flags |= AT24_FLAG_NO_RDROL; |
---|
627 | | - |
---|
628 | | - err = device_property_read_u32(dev, "address-width", &val); |
---|
629 | | - if (!err) { |
---|
630 | | - switch (val) { |
---|
631 | | - case 8: |
---|
632 | | - if (chip->flags & AT24_FLAG_ADDR16) |
---|
633 | | - dev_warn(dev, "Override address width to be 8, while default is 16\n"); |
---|
634 | | - chip->flags &= ~AT24_FLAG_ADDR16; |
---|
635 | | - break; |
---|
636 | | - case 16: |
---|
637 | | - chip->flags |= AT24_FLAG_ADDR16; |
---|
638 | | - break; |
---|
639 | | - default: |
---|
640 | | - dev_warn(dev, "Bad \"address-width\" property: %u\n", |
---|
641 | | - val); |
---|
642 | | - } |
---|
643 | | - } |
---|
644 | | - |
---|
645 | | - err = device_property_read_u32(dev, "size", &val); |
---|
646 | | - if (!err) |
---|
647 | | - chip->byte_len = val; |
---|
648 | | - |
---|
649 | | - err = device_property_read_u32(dev, "pagesize", &val); |
---|
650 | | - if (!err) { |
---|
651 | | - chip->page_size = val; |
---|
652 | | - } else { |
---|
653 | | - /* |
---|
654 | | - * This is slow, but we can't know all eeproms, so we better |
---|
655 | | - * play safe. Specifying custom eeprom-types via platform_data |
---|
656 | | - * is recommended anyhow. |
---|
657 | | - */ |
---|
658 | | - chip->page_size = 1; |
---|
659 | | - } |
---|
660 | | -} |
---|
661 | | - |
---|
662 | | -static int at24_get_pdata(struct device *dev, struct at24_platform_data *pdata) |
---|
| 657 | +static const struct at24_chip_data *at24_get_chip_data(struct device *dev) |
---|
663 | 658 | { |
---|
664 | 659 | struct device_node *of_node = dev->of_node; |
---|
665 | 660 | const struct at24_chip_data *cdata; |
---|
666 | 661 | const struct i2c_device_id *id; |
---|
667 | | - struct at24_platform_data *pd; |
---|
668 | | - |
---|
669 | | - pd = dev_get_platdata(dev); |
---|
670 | | - if (pd) { |
---|
671 | | - memcpy(pdata, pd, sizeof(*pdata)); |
---|
672 | | - return 0; |
---|
673 | | - } |
---|
674 | 662 | |
---|
675 | 663 | id = i2c_match_id(at24_ids, to_i2c_client(dev)); |
---|
676 | 664 | |
---|
.. | .. |
---|
687 | 675 | cdata = acpi_device_get_match_data(dev); |
---|
688 | 676 | |
---|
689 | 677 | if (!cdata) |
---|
690 | | - return -ENODEV; |
---|
| 678 | + return ERR_PTR(-ENODEV); |
---|
691 | 679 | |
---|
692 | | - pdata->byte_len = cdata->byte_len; |
---|
693 | | - pdata->flags = cdata->flags; |
---|
694 | | - at24_properties_to_pdata(dev, pdata); |
---|
695 | | - |
---|
696 | | - return 0; |
---|
697 | | -} |
---|
698 | | - |
---|
699 | | -static void at24_remove_dummy_clients(struct at24_data *at24) |
---|
700 | | -{ |
---|
701 | | - int i; |
---|
702 | | - |
---|
703 | | - for (i = 1; i < at24->num_addresses; i++) |
---|
704 | | - i2c_unregister_device(at24->client[i].client); |
---|
| 680 | + return cdata; |
---|
705 | 681 | } |
---|
706 | 682 | |
---|
707 | 683 | static int at24_make_dummy_client(struct at24_data *at24, unsigned int index, |
---|
708 | 684 | struct regmap_config *regmap_config) |
---|
709 | 685 | { |
---|
710 | 686 | struct i2c_client *base_client, *dummy_client; |
---|
711 | | - unsigned short int addr; |
---|
712 | 687 | struct regmap *regmap; |
---|
713 | 688 | struct device *dev; |
---|
714 | 689 | |
---|
715 | 690 | base_client = at24->client[0].client; |
---|
716 | 691 | dev = &base_client->dev; |
---|
717 | | - addr = base_client->addr + index; |
---|
718 | 692 | |
---|
719 | | - dummy_client = i2c_new_dummy(base_client->adapter, |
---|
720 | | - base_client->addr + index); |
---|
721 | | - if (!dummy_client) { |
---|
722 | | - dev_err(dev, "address 0x%02x unavailable\n", addr); |
---|
723 | | - return -EADDRINUSE; |
---|
724 | | - } |
---|
| 693 | + dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter, |
---|
| 694 | + base_client->addr + index); |
---|
| 695 | + if (IS_ERR(dummy_client)) |
---|
| 696 | + return PTR_ERR(dummy_client); |
---|
725 | 697 | |
---|
726 | 698 | regmap = devm_regmap_init_i2c(dummy_client, regmap_config); |
---|
727 | | - if (IS_ERR(regmap)) { |
---|
728 | | - i2c_unregister_device(dummy_client); |
---|
| 699 | + if (IS_ERR(regmap)) |
---|
729 | 700 | return PTR_ERR(regmap); |
---|
730 | | - } |
---|
731 | 701 | |
---|
732 | 702 | at24->client[index].client = dummy_client; |
---|
733 | 703 | at24->client[index].regmap = regmap; |
---|
.. | .. |
---|
762 | 732 | { |
---|
763 | 733 | struct regmap_config regmap_config = { }; |
---|
764 | 734 | struct nvmem_config nvmem_config = { }; |
---|
765 | | - struct at24_platform_data pdata = { }; |
---|
| 735 | + u32 byte_len, page_size, flags, addrw; |
---|
| 736 | + const struct at24_chip_data *cdata; |
---|
766 | 737 | struct device *dev = &client->dev; |
---|
767 | 738 | bool i2c_fn_i2c, i2c_fn_block; |
---|
768 | 739 | unsigned int i, num_addresses; |
---|
769 | 740 | struct at24_data *at24; |
---|
770 | 741 | struct regmap *regmap; |
---|
771 | | - size_t at24_size; |
---|
772 | 742 | bool writable; |
---|
773 | 743 | u8 test_byte; |
---|
774 | 744 | int err; |
---|
775 | 745 | |
---|
776 | | - printk("ben %s ...\n", __func__); |
---|
777 | 746 | i2c_fn_i2c = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); |
---|
778 | 747 | i2c_fn_block = i2c_check_functionality(client->adapter, |
---|
779 | 748 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK); |
---|
780 | 749 | |
---|
781 | | - err = at24_get_pdata(dev, &pdata); |
---|
| 750 | + cdata = at24_get_chip_data(dev); |
---|
| 751 | + if (IS_ERR(cdata)) |
---|
| 752 | + return PTR_ERR(cdata); |
---|
| 753 | + |
---|
| 754 | + err = device_property_read_u32(dev, "pagesize", &page_size); |
---|
782 | 755 | if (err) |
---|
783 | | - return err; |
---|
| 756 | + /* |
---|
| 757 | + * This is slow, but we can't know all eeproms, so we better |
---|
| 758 | + * play safe. Specifying custom eeprom-types via device tree |
---|
| 759 | + * or properties is recommended anyhow. |
---|
| 760 | + */ |
---|
| 761 | + page_size = 1; |
---|
| 762 | + |
---|
| 763 | + flags = cdata->flags; |
---|
| 764 | + if (device_property_present(dev, "read-only")) |
---|
| 765 | + flags |= AT24_FLAG_READONLY; |
---|
| 766 | + if (device_property_present(dev, "no-read-rollover")) |
---|
| 767 | + flags |= AT24_FLAG_NO_RDROL; |
---|
| 768 | + |
---|
| 769 | + err = device_property_read_u32(dev, "address-width", &addrw); |
---|
| 770 | + if (!err) { |
---|
| 771 | + switch (addrw) { |
---|
| 772 | + case 8: |
---|
| 773 | + if (flags & AT24_FLAG_ADDR16) |
---|
| 774 | + dev_warn(dev, |
---|
| 775 | + "Override address width to be 8, while default is 16\n"); |
---|
| 776 | + flags &= ~AT24_FLAG_ADDR16; |
---|
| 777 | + break; |
---|
| 778 | + case 16: |
---|
| 779 | + flags |= AT24_FLAG_ADDR16; |
---|
| 780 | + break; |
---|
| 781 | + default: |
---|
| 782 | + dev_warn(dev, "Bad \"address-width\" property: %u\n", |
---|
| 783 | + addrw); |
---|
| 784 | + } |
---|
| 785 | + } |
---|
| 786 | + |
---|
| 787 | + err = device_property_read_u32(dev, "size", &byte_len); |
---|
| 788 | + if (err) |
---|
| 789 | + byte_len = cdata->byte_len; |
---|
784 | 790 | |
---|
785 | 791 | if (!i2c_fn_i2c && !i2c_fn_block) |
---|
786 | | - pdata.page_size = 1; |
---|
| 792 | + page_size = 1; |
---|
787 | 793 | |
---|
788 | | - if (!pdata.page_size) { |
---|
| 794 | + if (!page_size) { |
---|
789 | 795 | dev_err(dev, "page_size must not be 0!\n"); |
---|
790 | 796 | return -EINVAL; |
---|
791 | 797 | } |
---|
792 | 798 | |
---|
793 | | - if (!is_power_of_2(pdata.page_size)) |
---|
| 799 | + if (!is_power_of_2(page_size)) |
---|
794 | 800 | dev_warn(dev, "page_size looks suspicious (no power of 2)!\n"); |
---|
795 | 801 | |
---|
796 | | - if (pdata.flags & AT24_FLAG_TAKE8ADDR) |
---|
797 | | - num_addresses = 8; |
---|
798 | | - else |
---|
799 | | - num_addresses = DIV_ROUND_UP(pdata.byte_len, |
---|
800 | | - (pdata.flags & AT24_FLAG_ADDR16) ? 65536 : 256); |
---|
| 802 | + err = device_property_read_u32(dev, "num-addresses", &num_addresses); |
---|
| 803 | + if (err) { |
---|
| 804 | + if (flags & AT24_FLAG_TAKE8ADDR) |
---|
| 805 | + num_addresses = 8; |
---|
| 806 | + else |
---|
| 807 | + num_addresses = DIV_ROUND_UP(byte_len, |
---|
| 808 | + (flags & AT24_FLAG_ADDR16) ? 65536 : 256); |
---|
| 809 | + } |
---|
801 | 810 | |
---|
802 | | - if ((pdata.flags & AT24_FLAG_SERIAL) && (pdata.flags & AT24_FLAG_MAC)) { |
---|
| 811 | + if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC)) { |
---|
803 | 812 | dev_err(dev, |
---|
804 | 813 | "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); |
---|
805 | 814 | return -EINVAL; |
---|
806 | 815 | } |
---|
807 | 816 | |
---|
808 | 817 | regmap_config.val_bits = 8; |
---|
809 | | - regmap_config.reg_bits = (pdata.flags & AT24_FLAG_ADDR16) ? 16 : 8; |
---|
| 818 | + regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8; |
---|
810 | 819 | regmap_config.disable_locking = true; |
---|
811 | 820 | |
---|
812 | 821 | regmap = devm_regmap_init_i2c(client, ®map_config); |
---|
813 | 822 | if (IS_ERR(regmap)) |
---|
814 | 823 | return PTR_ERR(regmap); |
---|
815 | 824 | |
---|
816 | | - at24_size = sizeof(*at24) + num_addresses * sizeof(struct at24_client); |
---|
817 | | - at24 = devm_kzalloc(dev, at24_size, GFP_KERNEL); |
---|
| 825 | + at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses), |
---|
| 826 | + GFP_KERNEL); |
---|
818 | 827 | if (!at24) |
---|
819 | 828 | return -ENOMEM; |
---|
820 | 829 | |
---|
821 | 830 | at24_private = at24; |
---|
822 | 831 | mutex_init(&at24->lock); |
---|
823 | | - at24->byte_len = pdata.byte_len; |
---|
824 | | - at24->page_size = pdata.page_size; |
---|
825 | | - at24->flags = pdata.flags; |
---|
| 832 | + at24->byte_len = byte_len; |
---|
| 833 | + at24->page_size = page_size; |
---|
| 834 | + at24->flags = flags; |
---|
| 835 | + at24->read_post = cdata->read_post; |
---|
826 | 836 | at24->num_addresses = num_addresses; |
---|
827 | | - at24->offset_adj = at24_get_offset_adj(pdata.flags, pdata.byte_len); |
---|
| 837 | + at24->offset_adj = at24_get_offset_adj(flags, byte_len); |
---|
828 | 838 | at24->client[0].client = client; |
---|
829 | 839 | at24->client[0].regmap = regmap; |
---|
830 | 840 | |
---|
831 | | - at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH); |
---|
832 | | - if (IS_ERR(at24->wp_gpio)) |
---|
833 | | - return PTR_ERR(at24->wp_gpio); |
---|
| 841 | + at24->vcc_reg = devm_regulator_get(dev, "vcc"); |
---|
| 842 | + if (IS_ERR(at24->vcc_reg)) |
---|
| 843 | + return PTR_ERR(at24->vcc_reg); |
---|
834 | 844 | |
---|
835 | | - writable = !(pdata.flags & AT24_FLAG_READONLY); |
---|
| 845 | + writable = !(flags & AT24_FLAG_READONLY); |
---|
836 | 846 | if (writable) { |
---|
837 | 847 | at24->write_max = min_t(unsigned int, |
---|
838 | | - pdata.page_size, at24_io_limit); |
---|
| 848 | + page_size, at24_io_limit); |
---|
839 | 849 | if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX) |
---|
840 | 850 | at24->write_max = I2C_SMBUS_BLOCK_MAX; |
---|
841 | 851 | } |
---|
.. | .. |
---|
843 | 853 | /* use dummy devices for multiple-address chips */ |
---|
844 | 854 | for (i = 1; i < num_addresses; i++) { |
---|
845 | 855 | err = at24_make_dummy_client(at24, i, ®map_config); |
---|
846 | | - if (err) { |
---|
847 | | - at24_remove_dummy_clients(at24); |
---|
| 856 | + if (err) |
---|
848 | 857 | return err; |
---|
849 | | - } |
---|
850 | 858 | } |
---|
851 | | - |
---|
852 | | - i2c_set_clientdata(client, at24); |
---|
853 | | - |
---|
854 | | - /* enable runtime pm */ |
---|
855 | | - pm_runtime_set_active(dev); |
---|
856 | | - pm_runtime_enable(dev); |
---|
857 | 859 | |
---|
858 | 860 | /* |
---|
859 | | - * Perform a one-byte test read to verify that the |
---|
860 | | - * chip is functional. |
---|
| 861 | + * We initialize nvmem_config.id to NVMEM_DEVID_AUTO even if the |
---|
| 862 | + * label property is set as some platform can have multiple eeproms |
---|
| 863 | + * with same label and we can not register each of those with same |
---|
| 864 | + * label. Failing to register those eeproms trigger cascade failure |
---|
| 865 | + * on such platform. |
---|
861 | 866 | */ |
---|
862 | | - err = at24_read(at24, 0, &test_byte, 1); |
---|
863 | | - pm_runtime_idle(dev); |
---|
864 | | - if (err) { |
---|
865 | | - err = -ENODEV; |
---|
866 | | - goto err_clients; |
---|
| 867 | + nvmem_config.id = NVMEM_DEVID_AUTO; |
---|
| 868 | + |
---|
| 869 | + if (device_property_present(dev, "label")) { |
---|
| 870 | + err = device_property_read_string(dev, "label", |
---|
| 871 | + &nvmem_config.name); |
---|
| 872 | + if (err) |
---|
| 873 | + return err; |
---|
| 874 | + } else { |
---|
| 875 | + nvmem_config.name = dev_name(dev); |
---|
867 | 876 | } |
---|
868 | 877 | |
---|
869 | | - nvmem_config.name = dev_name(dev); |
---|
| 878 | + nvmem_config.type = NVMEM_TYPE_EEPROM; |
---|
870 | 879 | nvmem_config.dev = dev; |
---|
871 | 880 | nvmem_config.read_only = !writable; |
---|
872 | | - nvmem_config.root_only = !(pdata.flags & AT24_FLAG_IRUGO); |
---|
| 881 | + nvmem_config.root_only = !(flags & AT24_FLAG_IRUGO); |
---|
873 | 882 | nvmem_config.owner = THIS_MODULE; |
---|
874 | 883 | nvmem_config.compat = true; |
---|
875 | 884 | nvmem_config.base_dev = dev; |
---|
.. | .. |
---|
878 | 887 | nvmem_config.priv = at24; |
---|
879 | 888 | nvmem_config.stride = 1; |
---|
880 | 889 | nvmem_config.word_size = 1; |
---|
881 | | - nvmem_config.size = pdata.byte_len; |
---|
| 890 | + nvmem_config.size = byte_len; |
---|
| 891 | + |
---|
| 892 | + i2c_set_clientdata(client, at24); |
---|
| 893 | + |
---|
| 894 | + err = regulator_enable(at24->vcc_reg); |
---|
| 895 | + if (err) { |
---|
| 896 | + dev_err(dev, "Failed to enable vcc regulator\n"); |
---|
| 897 | + return err; |
---|
| 898 | + } |
---|
| 899 | + |
---|
| 900 | + /* enable runtime pm */ |
---|
| 901 | + pm_runtime_set_active(dev); |
---|
| 902 | + pm_runtime_enable(dev); |
---|
882 | 903 | |
---|
883 | 904 | at24->nvmem = devm_nvmem_register(dev, &nvmem_config); |
---|
884 | 905 | if (IS_ERR(at24->nvmem)) { |
---|
885 | | - err = PTR_ERR(at24->nvmem); |
---|
886 | | - goto err_clients; |
---|
| 906 | + pm_runtime_disable(dev); |
---|
| 907 | + if (!pm_runtime_status_suspended(dev)) |
---|
| 908 | + regulator_disable(at24->vcc_reg); |
---|
| 909 | + return PTR_ERR(at24->nvmem); |
---|
887 | 910 | } |
---|
888 | 911 | |
---|
889 | | - dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n", |
---|
890 | | - pdata.byte_len, client->name, |
---|
891 | | - writable ? "writable" : "read-only", at24->write_max); |
---|
| 912 | + /* |
---|
| 913 | + * Perform a one-byte test read to verify that the |
---|
| 914 | + * chip is functional. |
---|
| 915 | + */ |
---|
| 916 | + err = at24_read(at24, 0, &test_byte, 1); |
---|
| 917 | + if (err) { |
---|
| 918 | + pm_runtime_disable(dev); |
---|
| 919 | + if (!pm_runtime_status_suspended(dev)) |
---|
| 920 | + regulator_disable(at24->vcc_reg); |
---|
| 921 | + return -ENODEV; |
---|
| 922 | + } |
---|
892 | 923 | |
---|
893 | | - /* export data to kernel code */ |
---|
894 | | - if (pdata.setup) |
---|
895 | | - pdata.setup(at24->nvmem, pdata.context); |
---|
| 924 | + pm_runtime_idle(dev); |
---|
| 925 | + |
---|
| 926 | + if (writable) |
---|
| 927 | + dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n", |
---|
| 928 | + byte_len, client->name, at24->write_max); |
---|
| 929 | + else |
---|
| 930 | + dev_info(dev, "%u byte %s EEPROM, read-only\n", |
---|
| 931 | + byte_len, client->name); |
---|
896 | 932 | |
---|
897 | 933 | return 0; |
---|
898 | | - |
---|
899 | | -err_clients: |
---|
900 | | - at24_remove_dummy_clients(at24); |
---|
901 | | - pm_runtime_disable(dev); |
---|
902 | | - |
---|
903 | | - return err; |
---|
904 | 934 | } |
---|
905 | 935 | |
---|
906 | 936 | static int at24_remove(struct i2c_client *client) |
---|
907 | 937 | { |
---|
908 | | - struct at24_data *at24; |
---|
| 938 | + struct at24_data *at24 = i2c_get_clientdata(client); |
---|
909 | 939 | |
---|
910 | | - at24 = i2c_get_clientdata(client); |
---|
911 | | - |
---|
912 | | - at24_remove_dummy_clients(at24); |
---|
913 | 940 | pm_runtime_disable(&client->dev); |
---|
| 941 | + if (!pm_runtime_status_suspended(&client->dev)) |
---|
| 942 | + regulator_disable(at24->vcc_reg); |
---|
914 | 943 | pm_runtime_set_suspended(&client->dev); |
---|
915 | 944 | |
---|
916 | 945 | return 0; |
---|
917 | 946 | } |
---|
918 | 947 | |
---|
| 948 | +static int __maybe_unused at24_suspend(struct device *dev) |
---|
| 949 | +{ |
---|
| 950 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 951 | + struct at24_data *at24 = i2c_get_clientdata(client); |
---|
| 952 | + |
---|
| 953 | + return regulator_disable(at24->vcc_reg); |
---|
| 954 | +} |
---|
| 955 | + |
---|
| 956 | +static int __maybe_unused at24_resume(struct device *dev) |
---|
| 957 | +{ |
---|
| 958 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 959 | + struct at24_data *at24 = i2c_get_clientdata(client); |
---|
| 960 | + |
---|
| 961 | + return regulator_enable(at24->vcc_reg); |
---|
| 962 | +} |
---|
| 963 | + |
---|
| 964 | +static const struct dev_pm_ops at24_pm_ops = { |
---|
| 965 | + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
---|
| 966 | + pm_runtime_force_resume) |
---|
| 967 | + SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL) |
---|
| 968 | +}; |
---|
| 969 | + |
---|
919 | 970 | static struct i2c_driver at24_driver = { |
---|
920 | 971 | .driver = { |
---|
921 | 972 | .name = "at24", |
---|
| 973 | + .pm = &at24_pm_ops, |
---|
922 | 974 | .of_match_table = at24_of_match, |
---|
923 | 975 | .acpi_match_table = ACPI_PTR(at24_acpi_ids), |
---|
924 | 976 | }, |
---|