1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <linux/mtd/spi-nor.h> |
4 | #include <linux/spi/spi.h> |
5 | #include <linux/spi/spi-mem.h> |
6 | #include <linux/sysfs.h> |
7 | |
8 | #include "core.h" |
9 | |
10 | static ssize_t manufacturer_show(struct device *dev, |
11 | struct device_attribute *attr, char *buf) |
12 | { |
13 | struct spi_device *spi = to_spi_device(dev); |
14 | struct spi_mem *spimem = spi_get_drvdata(spi); |
15 | struct spi_nor *nor = spi_mem_get_drvdata(mem: spimem); |
16 | |
17 | return sysfs_emit(buf, fmt: "%s\n" , nor->manufacturer->name); |
18 | } |
19 | static DEVICE_ATTR_RO(manufacturer); |
20 | |
21 | static ssize_t partname_show(struct device *dev, |
22 | struct device_attribute *attr, char *buf) |
23 | { |
24 | struct spi_device *spi = to_spi_device(dev); |
25 | struct spi_mem *spimem = spi_get_drvdata(spi); |
26 | struct spi_nor *nor = spi_mem_get_drvdata(mem: spimem); |
27 | |
28 | return sysfs_emit(buf, fmt: "%s\n" , nor->info->name); |
29 | } |
30 | static DEVICE_ATTR_RO(partname); |
31 | |
32 | static ssize_t jedec_id_show(struct device *dev, |
33 | struct device_attribute *attr, char *buf) |
34 | { |
35 | struct spi_device *spi = to_spi_device(dev); |
36 | struct spi_mem *spimem = spi_get_drvdata(spi); |
37 | struct spi_nor *nor = spi_mem_get_drvdata(mem: spimem); |
38 | const u8 *id = nor->info->id ? nor->info->id->bytes : nor->id; |
39 | u8 id_len = nor->info->id ? nor->info->id->len : SPI_NOR_MAX_ID_LEN; |
40 | |
41 | return sysfs_emit(buf, fmt: "%*phN\n" , id_len, id); |
42 | } |
43 | static DEVICE_ATTR_RO(jedec_id); |
44 | |
45 | static struct attribute *spi_nor_sysfs_entries[] = { |
46 | &dev_attr_manufacturer.attr, |
47 | &dev_attr_partname.attr, |
48 | &dev_attr_jedec_id.attr, |
49 | NULL |
50 | }; |
51 | |
52 | static ssize_t sfdp_read(struct file *filp, struct kobject *kobj, |
53 | struct bin_attribute *bin_attr, char *buf, |
54 | loff_t off, size_t count) |
55 | { |
56 | struct spi_device *spi = to_spi_device(kobj_to_dev(kobj)); |
57 | struct spi_mem *spimem = spi_get_drvdata(spi); |
58 | struct spi_nor *nor = spi_mem_get_drvdata(mem: spimem); |
59 | struct sfdp *sfdp = nor->sfdp; |
60 | size_t sfdp_size = sfdp->num_dwords * sizeof(*sfdp->dwords); |
61 | |
62 | return memory_read_from_buffer(to: buf, count, ppos: &off, from: nor->sfdp->dwords, |
63 | available: sfdp_size); |
64 | } |
65 | static BIN_ATTR_RO(sfdp, 0); |
66 | |
67 | static struct bin_attribute *spi_nor_sysfs_bin_entries[] = { |
68 | &bin_attr_sfdp, |
69 | NULL |
70 | }; |
71 | |
72 | static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj, |
73 | struct attribute *attr, int n) |
74 | { |
75 | struct spi_device *spi = to_spi_device(kobj_to_dev(kobj)); |
76 | struct spi_mem *spimem = spi_get_drvdata(spi); |
77 | struct spi_nor *nor = spi_mem_get_drvdata(mem: spimem); |
78 | |
79 | if (attr == &dev_attr_manufacturer.attr && !nor->manufacturer) |
80 | return 0; |
81 | if (attr == &dev_attr_jedec_id.attr && !nor->info->id && !nor->id) |
82 | return 0; |
83 | |
84 | return 0444; |
85 | } |
86 | |
87 | static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj, |
88 | struct bin_attribute *attr, int n) |
89 | { |
90 | struct spi_device *spi = to_spi_device(kobj_to_dev(kobj)); |
91 | struct spi_mem *spimem = spi_get_drvdata(spi); |
92 | struct spi_nor *nor = spi_mem_get_drvdata(mem: spimem); |
93 | |
94 | if (attr == &bin_attr_sfdp && nor->sfdp) |
95 | return 0444; |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | static const struct attribute_group spi_nor_sysfs_group = { |
101 | .name = "spi-nor" , |
102 | .is_visible = spi_nor_sysfs_is_visible, |
103 | .is_bin_visible = spi_nor_sysfs_is_bin_visible, |
104 | .attrs = spi_nor_sysfs_entries, |
105 | .bin_attrs = spi_nor_sysfs_bin_entries, |
106 | }; |
107 | |
108 | const struct attribute_group *spi_nor_sysfs_groups[] = { |
109 | &spi_nor_sysfs_group, |
110 | NULL |
111 | }; |
112 | |