]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tas2770sw-android/tas2770sw-android.git/blob - tas2770-regmap.c
Read/Write registers by i2c directly. Add dac volume control.
[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_PowerControl:
65         case TAS2770_BrownOutPreventionReg0:/* has a self clearing bit */
66         case TAS2770_LiveInterruptReg0:
67         case TAS2770_LiveInterruptReg1:
68         case TAS2770_LatchedInterruptReg0:/* Sticky interrupt flags */
69         case TAS2770_LatchedInterruptReg1:/* Sticky interrupt flags */
70         case TAS2770_VBATMSB:
71         case TAS2770_VBATLSB:
72         case TAS2770_TEMPMSB:
73         case TAS2770_TEMPLSB:
74                 return true;
75         }
76         return false;
77 }
79 static bool tas2770_writeable(struct device *dev, unsigned int reg)
80 {
81         switch (reg) {
82         case TAS2770_LiveInterruptReg0:
83         case TAS2770_LiveInterruptReg1:
84         case TAS2770_LatchedInterruptReg0:
85         case TAS2770_LatchedInterruptReg1:
86         case TAS2770_VBATMSB:
87         case TAS2770_VBATLSB:
88         case TAS2770_TEMPMSB:
89         case TAS2770_TEMPLSB:
90         case TAS2770_TDMClockdetectionmonitor:
91         case TAS2770_RevisionandPGID:
92                 return false;
93         }
94         return true;
95 }
96 static const struct regmap_config tas2770_i2c_regmap = {
97         .reg_bits = 8,
98         .val_bits = 8,
99         .writeable_reg = tas2770_writeable,
100         .volatile_reg = tas2770_volatile,
101         .reg_defaults = tas2770_reg_defaults,
102         .num_reg_defaults = ARRAY_SIZE(tas2770_reg_defaults),
103         .cache_type = REGCACHE_RBTREE,
104         .max_register = 1 * 128,
105 };
108 static void tas2770_hw_reset(struct tas2770_priv *pTAS2770)
110         if (gpio_is_valid(pTAS2770->mnResetGPIO)) {
111                 gpio_direction_output(pTAS2770->mnResetGPIO, 0);
112                 msleep(5);
113                 gpio_direction_output(pTAS2770->mnResetGPIO, 1);
114                 msleep(2);
115         }
117         pTAS2770->mnCurrentBook = -1;
118         pTAS2770->mnCurrentPage = -1;
121 void tas2770_enableIRQ(struct tas2770_priv *pTAS2770, bool enable)
123         if (enable) {
124                 if (pTAS2770->mbIRQEnable)
125                         return;
127                 if (gpio_is_valid(pTAS2770->mnIRQGPIO))
128                         enable_irq(pTAS2770->mnIRQ);
130                 schedule_delayed_work(&pTAS2770->irq_work, msecs_to_jiffies(10));
131                 pTAS2770->mbIRQEnable = true;
132         } else {
133                 if (!pTAS2770->mbIRQEnable)
134                         return;
136                 if (gpio_is_valid(pTAS2770->mnIRQGPIO))
137                         disable_irq_nosync(pTAS2770->mnIRQ);
138                 pTAS2770->mbIRQEnable = false;
139         }
142 static void irq_work_routine(struct work_struct *work)
144         struct tas2770_priv *pTAS2770 =
145                 container_of(work, struct tas2770_priv, irq_work.work);
147 #ifdef CONFIG_TAS2770_CODEC
148         mutex_lock(&pTAS2770->codec_lock);
149 #endif
151         if (pTAS2770->mbRuntimeSuspend) {
152                 dev_info(pTAS2770->dev, "%s, Runtime Suspended\n", __func__);
153                 goto end;
154         }
156         if (!pTAS2770->mbPowerUp) {
157                 dev_info(pTAS2770->dev, "%s, device not powered\n", __func__);
158                 goto end;
159         }
161 end:
162 #ifdef CONFIG_TAS2770_CODEC
163         mutex_unlock(&pTAS2770->codec_lock);
164 #endif
167 static enum hrtimer_restart timer_func(struct hrtimer *timer)
169         struct tas2770_priv *pTAS2770 = container_of(timer,
170                 struct tas2770_priv, mtimer);
172         if (pTAS2770->mbPowerUp) {
173                 if (!delayed_work_pending(&pTAS2770->irq_work))
174                         schedule_delayed_work(&pTAS2770->irq_work,
175                                 msecs_to_jiffies(20));
176         }
178         return HRTIMER_NORESTART;
181 static irqreturn_t tas2770_irq_handler(int irq, void *dev_id)
183         struct tas2770_priv *pTAS2770 = (struct tas2770_priv *)dev_id;
185         tas2770_enableIRQ(pTAS2770, false);
187         /* get IRQ status after 100 ms */
188         if (!delayed_work_pending(&pTAS2770->irq_work))
189                 schedule_delayed_work(&pTAS2770->irq_work,
190                         msecs_to_jiffies(100));
192         return IRQ_HANDLED;
195 static int tas2770_runtime_suspend(struct tas2770_priv *pTAS2770)
197         dev_dbg(pTAS2770->dev, "%s\n", __func__);
199         pTAS2770->mbRuntimeSuspend = true;
201         if (hrtimer_active(&pTAS2770->mtimer)) {
202                 dev_dbg(pTAS2770->dev, "cancel die temp timer\n");
203                 hrtimer_cancel(&pTAS2770->mtimer);
204         }
206         if (delayed_work_pending(&pTAS2770->irq_work)) {
207                 dev_dbg(pTAS2770->dev, "cancel IRQ work\n");
208                 cancel_delayed_work_sync(&pTAS2770->irq_work);
209         }
211         return 0;
214 #define CHECK_PERIOD    5000    /* 5 second */
215 static int tas2770_runtime_resume(struct tas2770_priv *pTAS2770)
217         dev_dbg(pTAS2770->dev, "%s\n", __func__);
219         if (pTAS2770->mbPowerUp) {
220                 if (!hrtimer_active(&pTAS2770->mtimer)) {
221                         hrtimer_start(&pTAS2770->mtimer,
222                                 ns_to_ktime((u64)CHECK_PERIOD * NSEC_PER_MSEC),
223                                 HRTIMER_MODE_REL);
224                 }
226         }
228         pTAS2770->mbRuntimeSuspend = false;
230         return 0;
233 static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *pTAS2770)
235         struct device_node *np = dev->of_node;
236         int rc = 0, ret = 0;
238         rc = of_property_read_u32(np, "ti,asi-format", &pTAS2770->mnASIFormat);
239         if (rc) {
240                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
241                         "ti,asi-format", np->full_name, rc);
242         } else {
243                 dev_dbg(pTAS2770->dev, "ti,asi-format=%d",
244                         pTAS2770->mnASIFormat);
245         }
247         pTAS2770->mnResetGPIO = of_get_named_gpio(np, "ti,reset-gpio", 0);
248         if (!gpio_is_valid(pTAS2770->mnResetGPIO)) {
249                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
250                         "ti,reset-gpio", np->full_name, pTAS2770->mnResetGPIO);
251         } else {
252                 dev_dbg(pTAS2770->dev, "ti,reset-gpio=%d",
253                         pTAS2770->mnResetGPIO);
254         }
256         pTAS2770->mnIRQGPIO = of_get_named_gpio(np, "ti,irq-gpio", 0);
257         if (!gpio_is_valid(pTAS2770->mnIRQGPIO)) {
258                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
259                         "ti,irq-gpio", np->full_name, pTAS2770->mnIRQGPIO);
260         } else {
261                 dev_dbg(pTAS2770->dev, "ti,irq-gpio=%d", pTAS2770->mnIRQGPIO);
262         }
264         of_property_read_u32(np, "ti,left-slot", &pTAS2770->mnLeftSlot);
265         if (rc) {
266                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
267                         "ti,left-slot", np->full_name, rc);
268         } else {
269                 dev_dbg(pTAS2770->dev, "ti,left-slot=%d",
270                         pTAS2770->mnLeftSlot);
271         }
273         of_property_read_u32(np, "ti,right-slot", &pTAS2770->mnRightSlot);
274         if (rc) {
275                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
276                         "ti,right-slot", np->full_name, rc);
277         } else {
278                 dev_dbg(pTAS2770->dev, "ti,right-slot=%d",
279                         pTAS2770->mnRightSlot);
280         }
282         of_property_read_u32(np, "ti,imon-slot-no", &pTAS2770->mnImon_slot_no);
283         if (rc) {
284                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
285                         "ti,imon-slot-no", np->full_name, rc);
286         } else {
287                 dev_dbg(pTAS2770->dev, "ti,imon-slot-no=%d",
288                         pTAS2770->mnImon_slot_no);
289         }
291         of_property_read_u32(np, "ti,vmon-slot-no", &pTAS2770->mnVmon_slot_no);
292         if (rc) {
293                 dev_err(pTAS2770->dev, "Looking up %s property in node %s failed %d\n",
294                         "ti,vmon-slot-no", np->full_name, rc);
295         } else {
296                 dev_dbg(pTAS2770->dev, "ti,vmon-slot-no=%d",
297                         pTAS2770->mnVmon_slot_no);
298         }
300         return ret;
303 static int tas2770_i2c_probe(struct i2c_client *client,
304                         const struct i2c_device_id *id)
306         struct tas2770_priv *pTAS2770;
307         int nResult;
309         dev_info(&client->dev, "%s enter\n", __func__);
311         pTAS2770 = devm_kzalloc(&client->dev,
312                 sizeof(struct tas2770_priv), GFP_KERNEL);
313         if (pTAS2770 == NULL) {
314                 nResult = -ENOMEM;
315                 goto end;
316         }
318         pTAS2770->dev = &client->dev;
319         i2c_set_clientdata(client, pTAS2770);
320         dev_set_drvdata(&client->dev, pTAS2770);
322         pTAS2770->regmap = devm_regmap_init_i2c(client, &tas2770_i2c_regmap);
323         if (IS_ERR(pTAS2770->regmap)) {
324                 nResult = PTR_ERR(pTAS2770->regmap);
325                 dev_err(&client->dev, "Failed to allocate register map: %d\n",
326                                         nResult);
327                 goto end;
328         }
330         if (client->dev.of_node)
331                 tas2770_parse_dt(&client->dev, pTAS2770);
333         if (gpio_is_valid(pTAS2770->mnResetGPIO)) {
334                 nResult = gpio_request(pTAS2770->mnResetGPIO, "TAS2770_RESET");
335                 if (nResult) {
336                         dev_err(pTAS2770->dev, "%s: Failed to request gpio %d\n",
337                                 __func__, pTAS2770->mnResetGPIO);
338                         nResult = -EINVAL;
339                         goto free_gpio;
340                 }
341         }
343         if (gpio_is_valid(pTAS2770->mnIRQGPIO)) {
344                 nResult = gpio_request(pTAS2770->mnIRQGPIO, "TAS2770-IRQ");
345                 if (nResult < 0) {
346                         dev_err(pTAS2770->dev, "%s: GPIO %d request error\n",
347                                 __func__, pTAS2770->mnIRQGPIO);
348                         goto free_gpio;
349                 }
350                 gpio_direction_input(pTAS2770->mnIRQGPIO);
351                 pTAS2770->mnIRQ = gpio_to_irq(pTAS2770->mnIRQGPIO);
352                 dev_dbg(pTAS2770->dev, "irq = %d\n", pTAS2770->mnIRQ);
353                 nResult = request_threaded_irq(pTAS2770->mnIRQ,
354                                         tas2770_irq_handler, NULL,
355                                         IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
356                                         client->name, pTAS2770);
357                 if (nResult < 0) {
358                         dev_err(pTAS2770->dev,
359                                 "request_irq failed, %d\n", nResult);
360                         goto free_gpio;
361                 }
362                 disable_irq_nosync(pTAS2770->mnIRQ);
363                 INIT_DELAYED_WORK(&pTAS2770->irq_work, irq_work_routine);
364         }
365         pTAS2770->mnAddr = client->addr;
366         pTAS2770->adapter = client->adapter;
367         pTAS2770->hw_reset = tas2770_hw_reset;
368         pTAS2770->enableIRQ = tas2770_enableIRQ;
369         pTAS2770->runtime_suspend = tas2770_runtime_suspend;
370         pTAS2770->runtime_resume = tas2770_runtime_resume;
371         pTAS2770->mnCh_size = 0;
372         pTAS2770->mnSlot_width = 0;
374         tas2770_hw_reset(pTAS2770);
376         mutex_init(&pTAS2770->dev_lock);
377         if (nResult < 0)
378                 goto destroy_mutex;
380 #ifdef CONFIG_TAS2770_CODEC
381         mutex_init(&pTAS2770->codec_lock);
382         tas2770_register_codec(pTAS2770);
383 #endif
385         hrtimer_init(&pTAS2770->mtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
386         pTAS2770->mtimer.function = timer_func;
388 destroy_mutex:
389         if (nResult < 0)
390                 mutex_destroy(&pTAS2770->dev_lock);
392 free_gpio:
393         if (nResult < 0) {
394                 if (gpio_is_valid(pTAS2770->mnResetGPIO))
395                         gpio_free(pTAS2770->mnResetGPIO);
396                 if (gpio_is_valid(pTAS2770->mnIRQGPIO))
397                         gpio_free(pTAS2770->mnIRQGPIO);
398         }
400 end:
401         return nResult;
404 static int tas2770_i2c_remove(struct i2c_client *client)
406         struct tas2770_priv *pTAS2770 = i2c_get_clientdata(client);
408         dev_info(pTAS2770->dev, "%s\n", __func__);
410 #ifdef CONFIG_TAS2770_CODEC
411         tas2770_deregister_codec(pTAS2770);
412         mutex_destroy(&pTAS2770->codec_lock);
413 #endif
415         if (gpio_is_valid(pTAS2770->mnResetGPIO))
416                 gpio_free(pTAS2770->mnResetGPIO);
417         if (gpio_is_valid(pTAS2770->mnIRQGPIO))
418                 gpio_free(pTAS2770->mnIRQGPIO);
420         return 0;
424 static const struct i2c_device_id tas2770_i2c_id[] = {
425         { "tas2770", 0},
426         { }
427 };
428 MODULE_DEVICE_TABLE(i2c, tas2770_i2c_id);
430 #if defined(CONFIG_OF)
431 static const struct of_device_id tas2770_of_match[] = {
432         { .compatible = "ti,tas2770" },
433         {},
434 };
435 MODULE_DEVICE_TABLE(of, tas2770_of_match);
436 #endif
439 static struct i2c_driver tas2770_i2c_driver = {
440         .driver = {
441                 .name   = "tas2770",
442                 .owner  = THIS_MODULE,
443 #if defined(CONFIG_OF)
444                 .of_match_table = of_match_ptr(tas2770_of_match),
445 #endif
446         },
447         .probe      = tas2770_i2c_probe,
448         .remove     = tas2770_i2c_remove,
449         .id_table   = tas2770_i2c_id,
450 };
452 module_i2c_driver(tas2770_i2c_driver);
454 MODULE_AUTHOR("Texas Instruments Inc.");
455 MODULE_DESCRIPTION("TAS2770 I2C Smart Amplifier driver");
456 MODULE_LICENSE("GPL v2");
457 #endif