8038b28cf0e37924bb42204bedef6c7fdecf2dc6
[tas2770sw-android/tas2770sw-android.git] / tas2770-regmap.c
1 /*
2  * ALSA SoC Texas Instruments TAS2770 20-W Digital Input Mono Class-D
3  * Audio Amplifier with Speaker I/V Sense
4  *
5  * Copyright (C) 2016 Texas Instruments, Inc.
6  *
7  * Author: saiprasad
8  *
9  * This package is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  */
18 #ifdef CONFIG_TAS2770_REGMAP
20 #define DEBUG
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/err.h>
24 #include <linux/init.h>
25 #include <linux/delay.h>
26 #include <linux/pm.h>
27 #include <linux/i2c.h>
28 #include <linux/gpio.h>
29 #include <linux/regulator/consumer.h>
30 #include <linux/firmware.h>
31 #include <linux/regmap.h>
32 #include <linux/of.h>
33 #include <linux/of_gpio.h>
34 #include <linux/slab.h>
35 #include <sound/soc.h>
37 #include "tas2770.h"
38 #include "tas2770-codec.h"
40 static const struct reg_default tas2770_reg_defaults[] = {
41         { TAS2770_Page, 0x00 },
42         { TAS2770_SoftwareReset, 0x00 },
43         { TAS2770_PowerControl, 0x0e },
44         { TAS2770_PlaybackConfigurationReg0, 0x10 },
45         { TAS2770_PlaybackConfigurationReg1, 0x01 },
46         { TAS2770_PlaybackConfigurationReg2, 0x00 },
47         { TAS2770_MiscConfigurationReg0, 0x07 },
48         { TAS2770_TDMConfigurationReg1, 0x02 },
49         { TAS2770_TDMConfigurationReg2, 0x0a },
50         { TAS2770_TDMConfigurationReg3, 0x10 },
51         { TAS2770_InterruptMaskReg0, 0xfc },
52         { TAS2770_InterruptMaskReg1, 0xb1 },
53         { TAS2770_InterruptConfiguration, 0x05 },
54         { TAS2770_MiscIRQ, 0x81 },
55         { TAS2770_ClockConfiguration, 0x0c },
57 };
59 static bool tas2770_volatile(struct device *dev, unsigned int reg)
60 {
61         switch (reg) {
62         case TAS2770_Page: /* regmap implementation requires this */
63         case TAS2770_SoftwareReset: /* always clears after write */
64         case TAS2770_BrownOutPreventionReg0:/* has a self clearing bit */
65         case TAS2770_LiveInterruptReg0:
66         case TAS2770_LiveInterruptReg1:
67         case TAS2770_LatchedInterruptReg0:/* Sticky interrupt flags */
68         case TAS2770_LatchedInterruptReg1:/* Sticky interrupt flags */
69         case TAS2770_VBATMSB:
70         case TAS2770_VBATLSB:
71         case TAS2770_TEMPMSB:
72         case TAS2770_TEMPLSB:
73                 return true;
74         }
75         return false;
76 }
78 static bool tas2770_writeable(struct device *dev, unsigned int reg)
79 {
80         switch (reg) {
81         case TAS2770_LiveInterruptReg0:
82         case TAS2770_LiveInterruptReg1:
83         case TAS2770_LatchedInterruptReg0:
84         case TAS2770_LatchedInterruptReg1:
85         case TAS2770_VBATMSB:
86         case TAS2770_VBATLSB:
87         case TAS2770_TEMPMSB:
88         case TAS2770_TEMPLSB:
89         case TAS2770_TDMClockdetectionmonitor:
90         case TAS2770_RevisionandPGID:
91                 return false;
92         }
93         return true;
94 }
95 static const struct regmap_config tas2770_i2c_regmap = {
96         .reg_bits = 8,
97         .val_bits = 8,
98         .writeable_reg = tas2770_writeable,
99         .volatile_reg = tas2770_volatile,
100         .reg_defaults = tas2770_reg_defaults,
101         .num_reg_defaults = ARRAY_SIZE(tas2770_reg_defaults),
102         .cache_type = REGCACHE_RBTREE,
103         .max_register = 1 * 128,
104 };
107 static void tas2770_hw_reset(struct tas2770_priv *pTAS2770)
109         if (gpio_is_valid(pTAS2770->mnResetGPIO)) {
110                 gpio_direction_output(pTAS2770->mnResetGPIO, 0);
111                 msleep(5);
112                 gpio_direction_output(pTAS2770->mnResetGPIO, 1);
113                 msleep(2);
114         }
116         pTAS2770->mnCurrentBook = -1;
117         pTAS2770->mnCurrentPage = -1;
120 void tas2770_enableIRQ(struct tas2770_priv *pTAS2770, bool enable)
122         if (enable) {
123                 if (pTAS2770->mbIRQEnable)
124                         return;
126                 if (gpio_is_valid(pTAS2770->mnIRQGPIO))
127                         enable_irq(pTAS2770->mnIRQ);
129                 schedule_delayed_work(&pTAS2770->irq_work, msecs_to_jiffies(10));
130                 pTAS2770->mbIRQEnable = true;
131         } else {
132                 if (!pTAS2770->mbIRQEnable)
133                         return;
135                 if (gpio_is_valid(pTAS2770->mnIRQGPIO))
136                         disable_irq_nosync(pTAS2770->mnIRQ);
137                 pTAS2770->mbIRQEnable = false;
138         }
141 static void irq_work_routine(struct work_struct *work)
143         struct tas2770_priv *pTAS2770 =
144                 container_of(work, struct tas2770_priv, irq_work.work);
146 #ifdef CONFIG_TAS2770_CODEC
147         mutex_lock(&pTAS2770->codec_lock);
148 #endif
150         if (pTAS2770->mbRuntimeSuspend) {
151                 dev_info(pTAS2770->dev, "%s, Runtime Suspended\n", __func__);
152                 goto end;
153         }
155         if (!pTAS2770->mbPowerUp) {
156                 dev_info(pTAS2770->dev, "%s, device not powered\n", __func__);
157                 goto end;
158         }
160 end:
161 #ifdef CONFIG_TAS2770_CODEC
162         mutex_unlock(&pTAS2770->codec_lock);
163 #endif
166 static enum hrtimer_restart timer_func(struct hrtimer *timer)
168         struct tas2770_priv *pTAS2770 = container_of(timer,
169                 struct tas2770_priv, mtimer);
171         if (pTAS2770->mbPowerUp) {
172                 if (!delayed_work_pending(&pTAS2770->irq_work))
173                         schedule_delayed_work(&pTAS2770->irq_work,
174                                 msecs_to_jiffies(20));
175         }
177         return HRTIMER_NORESTART;
180 static irqreturn_t tas2770_irq_handler(int irq, void *dev_id)
182         struct tas2770_priv *pTAS2770 = (struct tas2770_priv *)dev_id;
184         tas2770_enableIRQ(pTAS2770, false);
186         /* get IRQ status after 100 ms */
187         if (!delayed_work_pending(&pTAS2770->irq_work))
188                 schedule_delayed_work(&pTAS2770->irq_work,
189                         msecs_to_jiffies(100));
191         return IRQ_HANDLED;
194 static int tas2770_runtime_suspend(struct tas2770_priv *pTAS2770)
196         dev_dbg(pTAS2770->dev, "%s\n", __func__);
198         pTAS2770->mbRuntimeSuspend = true;
200         if (hrtimer_active(&pTAS2770->mtimer)) {
201                 dev_dbg(pTAS2770->dev, "cancel die temp timer\n");
202                 hrtimer_cancel(&pTAS2770->mtimer);
203         }
205         if (delayed_work_pending(&pTAS2770->irq_work)) {
206                 dev_dbg(pTAS2770->dev, "cancel IRQ work\n");
207                 cancel_delayed_work_sync(&pTAS2770->irq_work);
208         }
210         return 0;
213 #define CHECK_PERIOD    5000    /* 5 second */
214 static int tas2770_runtime_resume(struct tas2770_priv *pTAS2770)
216         dev_dbg(pTAS2770->dev, "%s\n", __func__);
218         if (pTAS2770->mbPowerUp) {
219                 if (!hrtimer_active(&pTAS2770->mtimer)) {
220                         hrtimer_start(&pTAS2770->mtimer,
221                                 ns_to_ktime((u64)CHECK_PERIOD * NSEC_PER_MSEC),
222                                 HRTIMER_MODE_REL);
223                 }
225         }
227         pTAS2770->mbRuntimeSuspend = false;
229         return 0;
232 static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *pTAS2770)
234         struct device_node *np = dev->of_node;
235         int rc = 0, ret = 0;
237         rc = of_property_read_u32(np, "ti,asi-format", &pTAS2770->mnASIFormat);
238         if (rc) {
239                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
240                         "ti,asi-format", np->full_name, rc);
241         } else {
242                 dev_dbg(pTAS2770->dev, "ti,asi-format=%d",
243                         pTAS2770->mnASIFormat);
244         }
246         pTAS2770->mnResetGPIO = of_get_named_gpio(np, "ti,reset-gpio", 0);
247         if (!gpio_is_valid(pTAS2770->mnResetGPIO)) {
248                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
249                         "ti,reset-gpio", np->full_name, pTAS2770->mnResetGPIO);
250         } else {
251                 dev_dbg(pTAS2770->dev, "ti,reset-gpio=%d",
252                         pTAS2770->mnResetGPIO);
253         }
255         pTAS2770->mnIRQGPIO = of_get_named_gpio(np, "ti,irq-gpio", 0);
256         if (!gpio_is_valid(pTAS2770->mnIRQGPIO)) {
257                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
258                         "ti,irq-gpio", np->full_name, pTAS2770->mnIRQGPIO);
259         } else {
260                 dev_dbg(pTAS2770->dev, "ti,irq-gpio=%d", pTAS2770->mnIRQGPIO);
261         }
263         of_property_read_u32(np, "ti,left-slot", &pTAS2770->mnLeftSlot);
264         if (rc) {
265                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
266                         "ti,left-slot", np->full_name, rc);
267         } else {
268                 dev_dbg(pTAS2770->dev, "ti,left-slot=%d",
269                         pTAS2770->mnLeftSlot);
270         }
272         of_property_read_u32(np, "ti,right-slot", &pTAS2770->mnRightSlot);
273         if (rc) {
274                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
275                         "ti,right-slot", np->full_name, rc);
276         } else {
277                 dev_dbg(pTAS2770->dev, "ti,right-slot=%d",
278                         pTAS2770->mnRightSlot);
279         }
281         of_property_read_u32(np, "ti,imon-slot-no", &pTAS2770->mnImon_slot_no);
282         if (rc) {
283                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
284                         "ti,imon-slot-no", np->full_name, rc);
285         } else {
286                 dev_dbg(pTAS2770->dev, "ti,imon-slot-no=%d",
287                         pTAS2770->mnImon_slot_no);
288         }
290         of_property_read_u32(np, "ti,vmon-slot-no", &pTAS2770->mnVmon_slot_no);
291         if (rc) {
292                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
293                         "ti,vmon-slot-no", np->full_name, rc);
294         } else {
295                 dev_dbg(pTAS2770->dev, "ti,vmon-slot-no=%d",
296                         pTAS2770->mnVmon_slot_no);
297         }
299         return ret;
302 static int tas2770_i2c_probe(struct i2c_client *client,
303                         const struct i2c_device_id *id)
305         struct tas2770_priv *pTAS2770;
306         int nResult;
308         dev_info(&client->dev, "%s enter\n", __func__);
310         pTAS2770 = devm_kzalloc(&client->dev,
311                 sizeof(struct tas2770_priv), GFP_KERNEL);
312         if (pTAS2770 == NULL) {
313                 nResult = -ENOMEM;
314                 goto end;
315         }
317         pTAS2770->dev = &client->dev;
318         i2c_set_clientdata(client, pTAS2770);
319         dev_set_drvdata(&client->dev, pTAS2770);
321         pTAS2770->regmap = devm_regmap_init_i2c(client, &tas2770_i2c_regmap);
322         if (IS_ERR(pTAS2770->regmap)) {
323                 nResult = PTR_ERR(pTAS2770->regmap);
324                 dev_err(&client->dev, "Failed to allocate register map: %d\n",
325                                         nResult);
326                 goto end;
327         }
329         if (client->dev.of_node)
330                 tas2770_parse_dt(&client->dev, pTAS2770);
332         if (gpio_is_valid(pTAS2770->mnResetGPIO)) {
333                 nResult = gpio_request(pTAS2770->mnResetGPIO, "TAS2770_RESET");
334                 if (nResult) {
335                         dev_err(pTAS2770->dev, "%s: Failed to request gpio %d\n",
336                                 __func__, pTAS2770->mnResetGPIO);
337                         nResult = -EINVAL;
338                         goto free_gpio;
339                 }
340         }
342         if (gpio_is_valid(pTAS2770->mnIRQGPIO)) {
343                 nResult = gpio_request(pTAS2770->mnIRQGPIO, "TAS2770-IRQ");
344                 if (nResult < 0) {
345                         dev_err(pTAS2770->dev, "%s: GPIO %d request error\n",
346                                 __func__, pTAS2770->mnIRQGPIO);
347                         goto free_gpio;
348                 }
349                 gpio_direction_input(pTAS2770->mnIRQGPIO);
350                 pTAS2770->mnIRQ = gpio_to_irq(pTAS2770->mnIRQGPIO);
351                 dev_dbg(pTAS2770->dev, "irq = %d\n", pTAS2770->mnIRQ);
352                 nResult = request_threaded_irq(pTAS2770->mnIRQ,
353                                         tas2770_irq_handler, NULL,
354                                         IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
355                                         client->name, pTAS2770);
356                 if (nResult < 0) {
357                         dev_err(pTAS2770->dev,
358                                 "request_irq failed, %d\n", nResult);
359                         goto free_gpio;
360                 }
361                 disable_irq_nosync(pTAS2770->mnIRQ);
362                 INIT_DELAYED_WORK(&pTAS2770->irq_work, irq_work_routine);
363         }
365         pTAS2770->hw_reset = tas2770_hw_reset;
366         pTAS2770->enableIRQ = tas2770_enableIRQ;
367         pTAS2770->runtime_suspend = tas2770_runtime_suspend;
368         pTAS2770->runtime_resume = tas2770_runtime_resume;
369         pTAS2770->mnCh_size = 0;
370         pTAS2770->mnSlot_width = 0;
372         tas2770_hw_reset(pTAS2770);
374         mutex_init(&pTAS2770->dev_lock);
375         if (nResult < 0)
376                 goto destroy_mutex;
378 #ifdef CONFIG_TAS2770_CODEC
379         mutex_init(&pTAS2770->codec_lock);
380         tas2770_register_codec(pTAS2770);
381 #endif
383         hrtimer_init(&pTAS2770->mtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
384         pTAS2770->mtimer.function = timer_func;
386 destroy_mutex:
387         if (nResult < 0)
388                 mutex_destroy(&pTAS2770->dev_lock);
390 free_gpio:
391         if (nResult < 0) {
392                 if (gpio_is_valid(pTAS2770->mnResetGPIO))
393                         gpio_free(pTAS2770->mnResetGPIO);
394                 if (gpio_is_valid(pTAS2770->mnIRQGPIO))
395                         gpio_free(pTAS2770->mnIRQGPIO);
396         }
398 end:
399         return nResult;
402 static int tas2770_i2c_remove(struct i2c_client *client)
404         struct tas2770_priv *pTAS2770 = i2c_get_clientdata(client);
406         dev_info(pTAS2770->dev, "%s\n", __func__);
408 #ifdef CONFIG_TAS2770_CODEC
409         tas2770_deregister_codec(pTAS2770);
410         mutex_destroy(&pTAS2770->codec_lock);
411 #endif
413         if (gpio_is_valid(pTAS2770->mnResetGPIO))
414                 gpio_free(pTAS2770->mnResetGPIO);
415         if (gpio_is_valid(pTAS2770->mnIRQGPIO))
416                 gpio_free(pTAS2770->mnIRQGPIO);
418         return 0;
422 static const struct i2c_device_id tas2770_i2c_id[] = {
423         { "tas2770", 0},
424         { }
425 };
426 MODULE_DEVICE_TABLE(i2c, tas2770_i2c_id);
428 #if defined(CONFIG_OF)
429 static const struct of_device_id tas2770_of_match[] = {
430         { .compatible = "ti,tas2770" },
431         {},
432 };
433 MODULE_DEVICE_TABLE(of, tas2770_of_match);
434 #endif
437 static struct i2c_driver tas2770_i2c_driver = {
438         .driver = {
439                 .name   = "tas2770",
440                 .owner  = THIS_MODULE,
441 #if defined(CONFIG_OF)
442                 .of_match_table = of_match_ptr(tas2770_of_match),
443 #endif
444         },
445         .probe      = tas2770_i2c_probe,
446         .remove     = tas2770_i2c_remove,
447         .id_table   = tas2770_i2c_id,
448 };
450 module_i2c_driver(tas2770_i2c_driver);
452 MODULE_AUTHOR("Texas Instruments Inc.");
453 MODULE_DESCRIPTION("TAS2770 I2C Smart Amplifier driver");
454 MODULE_LICENSE("GPL v2");
455 #endif