]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/clk/idt/clk-idt8t49n24x-debugfs.c
clk: Add ccf driver for IDT 8T49N24x UFT
[zynq/linux.git] / drivers / clk / idt / clk-idt8t49n24x-debugfs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* clk-idt8t49n24x-debugfs.c - Debugfs support for 8T49N24x
3  *
4  * Copyright (C) 2018, Integrated Device Technology, Inc. <david.cater@idt.com>
5  *
6  * See https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
7  * This program is distributed "AS IS" and  WITHOUT ANY WARRANTY;
8  * including the implied warranties of MERCHANTABILITY, FITNESS FOR
9  * A PARTICULAR PURPOSE, or NON-INFRINGEMENT.
10  */
11
12 #include <linux/debugfs.h>
13 #include <linux/i2c.h>
14 #include <linux/regmap.h>
15 #include <linux/slab.h>
16
17 #include "clk-idt8t49n24x-debugfs.h"
18
19 struct clk_idt24x_chip *idt24x_chip_fordebugfs;
20
21 static int idt24x_read_all_settings(
22         struct clk_idt24x_chip *chip, char *output_buffer, int count)
23 {
24         u8 settings[NUM_CONFIG_REGISTERS];
25         int err = 0;
26         int x;
27
28         err = regmap_bulk_read(
29                 chip->regmap, 0x0, settings, NUM_CONFIG_REGISTERS);
30         if (!err) {
31                 output_buffer[0] = '\0';
32                 for (x = 0; x < ARRAY_SIZE(settings); x++) {
33                         char dbg[4];
34
35                         if ((strlen(output_buffer) + 4) > count)
36                                 return -EINVAL;
37                         sprintf(dbg, "%02x ", settings[x]);
38                         strcat(output_buffer, dbg);
39                 }
40         }
41         return err;
42 }
43
44 /**
45  * idt24x_debugfs_writer_action - Write handler for the "action" debugfs file.
46  * @fp:                 file pointer
47  * @user_buffer:        buffer of text written to file
48  * @count:              size of text in buffer
49  * @position:           pass in current position, return new position
50  *
51  * Return: result of call to simple_write_to_buffer
52  *
53  * Use the "action" file as a trigger for setting all requested
54  * rates. The driver doesn't get any notification when the files
55  * representing the Qx outputs are written to, so something else is
56  * needed to notify the driver that the device should be udpated.
57  *
58  * It doesn't matter what you write to the action debugs file. When the
59  * handler is called, the device will be updated.
60  */
61 static ssize_t idt24x_debugfs_writer_action(
62         struct file *fp, const char __user *user_buffer,
63         size_t count, loff_t *position)
64 {
65         int err = 0;
66         int x;
67         u32 freq;
68         bool needs_update = true;
69         struct i2c_client *client = idt24x_chip_fordebugfs->i2c_client;
70
71         if (count > DEBUGFS_BUFFER_LENGTH)
72                 return -EINVAL;
73
74         for (x = 0; x < NUM_OUTPUTS; x++) {
75                 freq = idt24x_chip_fordebugfs->clk[x].debug_freq;
76                 if (freq) {
77                         needs_update = false;
78                         dev_dbg(&client->dev,
79                                 "%s: calling clk_set_rate with debug frequency for Q%i",
80                                 __func__, x);
81                         err = clk_set_rate(
82                                 idt24x_chip_fordebugfs->clk[x].hw.clk, freq);
83                         if (err) {
84                                 dev_err(&client->dev,
85                                         "error calling clk_set_rate for Q%i (%i)\n",
86                                         x, err);
87                         }
88                 } else {
89                         needs_update = true;
90                         idt24x_chip_fordebugfs->clk[x].requested = 0;
91                         dev_dbg(&client->dev,
92                                 "%s: debug frequency for Q%i not set; make sure clock is disabled",
93                                 __func__, x);
94                 }
95         }
96
97         if (needs_update) {
98                 dev_dbg(&client->dev,
99                         "%s: calling idt24x_set_frequency to ensure any clocks that should be disabled are turned off.",
100                         __func__);
101                 err = idt24x_set_frequency(idt24x_chip_fordebugfs);
102                 if (err) {
103                         dev_err(&idt24x_chip_fordebugfs->i2c_client->dev,
104                                 "%s: error calling idt24x_set_frequency (%i)\n",
105                                 __func__, err);
106                         return err;
107                 }
108         }
109
110         return simple_write_to_buffer(
111                 idt24x_chip_fordebugfs->dbg_cache, DEBUGFS_BUFFER_LENGTH,
112                 position, user_buffer, count);
113 }
114
115 /**
116  * idt24x_debugfs_reader_action - Read the "action" debugfs file.
117  * @fp:                 file pointer
118  * @user_buffer:        buffer of text written to file
119  * @count:              size of text in buffer
120  * @position:           pass in current position, return new position
121  *
122  * Return: whatever was last written to the "action" debugfs file.
123  */
124 static ssize_t idt24x_debugfs_reader_action(
125         struct file *fp, char __user *user_buffer, size_t count,
126         loff_t *position)
127 {
128         return simple_read_from_buffer(
129                 user_buffer, count, position, idt24x_chip_fordebugfs->dbg_cache,
130                 DEBUGFS_BUFFER_LENGTH);
131 }
132
133 /**
134  * idt24x_debugfs_reader_map - display the current registers on the device
135  * @fp:                 file pointer
136  * @user_buffer:        buffer of text written to file
137  * @count:              size of text in buffer
138  * @position:           pass in current position, return new position
139  *
140  * Reads the current register map from the attached chip via I2C and
141  * returns it.
142  *
143  * Return: result of call to simple_read_from_buffer
144  */
145 static ssize_t idt24x_debugfs_reader_map(
146         struct file *fp, char __user *user_buffer, size_t count,
147         loff_t *position)
148 {
149         int err = 0;
150         char *buf = kzalloc(5000, GFP_KERNEL);
151
152         dev_dbg(&idt24x_chip_fordebugfs->i2c_client->dev,
153                 "calling idt24x_read_all_settings (count: %zu)\n", count);
154         err = idt24x_read_all_settings(idt24x_chip_fordebugfs, buf, 5000);
155         if (err) {
156                 dev_err(&idt24x_chip_fordebugfs->i2c_client->dev,
157                         "error calling idt24x_read_all_settings (%i)\n", err);
158                 return 0;
159         }
160         /* TMGCDR-1456. We're returning 1 byte too few. */
161         err = simple_read_from_buffer(
162                 user_buffer, count, position, buf, strlen(buf));
163         kfree(buf);
164         return err;
165 }
166
167 /**
168  * idt24x_handle_i2c_debug_token - process "token" written to the i2c file
169  * @dev:        pointer to device structure
170  * @token:      pointer to current char being examined
171  * @reg:        pass in current register, or return register from token.
172  * @val:        resulting array of bytes being parsed
173  * @nextbyte:   position in val array to store next byte
174  *
175  * Utility function to operate on the current "token" (from within a
176  * space-delimited string) written to the i2c debugfs file. It will
177  * either be a register offset or a byte to be added to the val array.
178  * If it is added to the val array, auto-increment nextbyte.
179  *
180  * Return:      0 for success
181  */
182 static int idt24x_handle_i2c_debug_token(
183         const struct device *dev, char *token, unsigned int *reg,
184         u8 val[], u16 *nextbyte)
185 {
186         int err = 0;
187
188         dev_dbg(dev, "got token (%s)\n", token);
189         if (*reg == -1) {
190                 err = kstrtouint(token, 16, reg);
191                 if (!err)
192                         dev_dbg(dev, "hex register address == 0x%x\n", *reg);
193         } else {
194                 u8 temp;
195
196                 err = kstrtou8(token, 16, &temp);
197                 if (!err) {
198                         dev_dbg(dev, "data byte == 0x%x\n", temp);
199                         val[*nextbyte] = temp;
200                         *nextbyte += 1;
201                 }
202         }
203         if (err == -ERANGE)
204                 dev_err(dev, "ERANGE error when parsing data\n");
205         else if (err == -EINVAL)
206                 dev_err(dev, "EINVAL error when parsing data\n");
207         else if (err)
208                 dev_err(dev, "error when parsing data: %i\n", err);
209         return err;
210 }
211
212 /**
213  * idt24x_debugfs_writer_i2c - debugfs handler for i2c file
214  * @fp:                 file pointer
215  * @user_buffer:        buffer of text written to file
216  * @count:              size of text in buffer
217  * @position:           pass in current position, return new position
218  *
219  * Handler for the "i2c" debugfs file. Write to this file to write bytes
220  * via I2C to a particular offset.
221  *
222  * Usage: echo 006c 01 02 0D FF > i2c
223  *
224  * First 4 chars are the 2-byte i2c register offset. Then follow that
225  * with a sequence of 2-char bytes in hex format that you want to write
226  * starting at that offset.
227  *
228  * Return: result of simple_write_to_buffer
229  */
230 static ssize_t idt24x_debugfs_writer_i2c(struct file *fp,
231                                          const char __user *user_buffer,
232                                          size_t count, loff_t *position)
233 {
234         int err = 0;
235         int x = 0;
236         int start = 0;
237         unsigned int reg = -1;
238         u8 val[WRITE_BLOCK_SIZE];
239         u16 nextbyte = 0;
240         char token[16];
241
242         if (count > DEBUGFS_BUFFER_LENGTH)
243                 return -EINVAL;
244
245         for (x = 0; x < count; x++) {
246                 token[x - start] = user_buffer[x];
247                 if (user_buffer[x] == ' ') {
248                         token[x - start] = '\0';
249                         err = idt24x_handle_i2c_debug_token(
250                                 &idt24x_chip_fordebugfs->i2c_client->dev,
251                                 token, &reg, val, &nextbyte);
252                         if (err)
253                                 break;
254                         start = x + 1;
255                 }
256         }
257
258         /* handle the last token */
259         if (!err) {
260                 token[count - start] = '\0';
261                 err = idt24x_handle_i2c_debug_token(
262                         &idt24x_chip_fordebugfs->i2c_client->dev, token, &reg,
263                         val, &nextbyte);
264         }
265
266         if (!err && reg != -1 && nextbyte > 0) {
267                 err = i2cwritebulk(
268                         idt24x_chip_fordebugfs->i2c_client,
269                         idt24x_chip_fordebugfs->regmap,
270                         reg, val, nextbyte);
271                 if (err) {
272                         dev_err(&idt24x_chip_fordebugfs->i2c_client->dev,
273                                 "error writing data chip (%i)\n", err);
274                         return err;
275                 }
276                 dev_dbg(&idt24x_chip_fordebugfs->i2c_client->dev,
277                         "successfully wrote i2c data to chip");
278         }
279
280         return simple_write_to_buffer(
281                 idt24x_chip_fordebugfs->dbg_cache, DEBUGFS_BUFFER_LENGTH,
282                 position, user_buffer, count);
283 }
284
285 static const struct file_operations idt24x_fops_debug_action = {
286         .read = idt24x_debugfs_reader_action,
287         .write = idt24x_debugfs_writer_action,
288 };
289
290 static const struct file_operations idt24x_fops_debug_map = {
291         .read = idt24x_debugfs_reader_map
292 };
293
294 static const struct file_operations idt24x_fops_debug_i2c = {
295         .write = idt24x_debugfs_writer_i2c,
296 };
297
298 /**
299  * idt24x_expose_via_debugfs - Set up all debugfs files
300  * @client:     pointer to i2c_client structure
301  * @chip:       Device data structure
302  *
303  * Sets up all debugfs files to use for debugging the driver.
304  * Return: error code. 0 if success or debugfs doesn't appear to be enabled.
305  */
306 int idt24x_expose_via_debugfs(struct i2c_client *client,
307                               struct clk_idt24x_chip *chip)
308 {
309         int output_num;
310
311         /*
312          * create root directory in /sys/kernel/debugfs
313          */
314         chip->debugfs_dirroot = debugfs_create_dir("idt24x", NULL);
315         if (!chip->debugfs_dirroot) {
316                 /* debugfs probably not enabled. Don't fail the probe. */
317                 return 0;
318         }
319
320         /*
321          * create files in the root directory. This requires read and
322          * write file operations
323          */
324         chip->debugfs_fileaction = debugfs_create_file(
325                 "action", 0644, chip->debugfs_dirroot, NULL,
326                 &idt24x_fops_debug_action);
327         if (!chip->debugfs_fileaction) {
328                 dev_err(&client->dev,
329                         "%s: error creating action file", __func__);
330                 return (-ENODEV);
331         }
332
333         chip->debugfs_map = debugfs_create_file(
334                 "map", 0444, chip->debugfs_dirroot, NULL,
335                 &idt24x_fops_debug_map);
336         if (!chip->debugfs_map) {
337                 dev_err(&client->dev,
338                         "%s: error creating map file", __func__);
339                 return (-ENODEV);
340         }
341
342         for (output_num = 0; output_num < NUM_OUTPUTS; output_num++) {
343                 char name[5];
344
345                 sprintf(name, "q%d", output_num);
346                 chip->debugfs_fileqfreq[output_num] = debugfs_create_u64(
347                         name, 0644, chip->debugfs_dirroot,
348                         &chip->clk[output_num].debug_freq);
349                 if (!chip->debugfs_fileqfreq[output_num]) {
350                         dev_err(&client->dev,
351                                 "%s: error creating %s debugfs file",
352                                 __func__, name);
353                         return (-ENODEV);
354                 }
355         }
356
357         chip->debugfs_filei2c = debugfs_create_file(
358                 "i2c", 0644, chip->debugfs_dirroot, NULL,
359                 &idt24x_fops_debug_i2c);
360         if (!chip->debugfs_filei2c) {
361                 dev_err(&client->dev,
362                         "%s: error creating i2c file", __func__);
363                 return (-ENODEV);
364         }
365
366         dev_dbg(&client->dev, "%s: success", __func__);
367         idt24x_chip_fordebugfs = chip;
368         return 0;
369 }
370
371 void idt24x_cleanup_debugfs(struct clk_idt24x_chip *chip)
372 {
373         debugfs_remove_recursive(chip->debugfs_dirroot);
374 }