@@ -32,6 +32,21 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
3232 { CS35L41_AMP_DIG_VOL_CTRL , 0x0000A678 }, // AMP_VOL_PCM Mute
3333};
3434
35+ /* Protection release cycle to get the speaker out of Safe-Mode */
36+ static void cs35l41_error_release (struct device * dev , struct regmap * regmap , unsigned int mask )
37+ {
38+ regmap_write (regmap , CS35L41_PROTECT_REL_ERR_IGN , 0 );
39+ regmap_set_bits (regmap , CS35L41_PROTECT_REL_ERR_IGN , mask );
40+ regmap_clear_bits (regmap , CS35L41_PROTECT_REL_ERR_IGN , mask );
41+ }
42+
43+ /* Clear all errors to release safe mode. Global Enable must be cleared first. */
44+ static void cs35l41_irq_release (struct cs35l41_hda * cs35l41 )
45+ {
46+ cs35l41_error_release (cs35l41 -> dev , cs35l41 -> regmap , cs35l41 -> irq_errors );
47+ cs35l41 -> irq_errors = 0 ;
48+ }
49+
3550static void cs35l41_hda_playback_hook (struct device * dev , int action )
3651{
3752 struct cs35l41_hda * cs35l41 = dev_get_drvdata (dev );
@@ -58,6 +73,7 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
5873 CS35L41_AMP_EN_MASK , 0 << CS35L41_AMP_EN_SHIFT );
5974 if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST )
6075 regmap_write (reg , CS35L41_GPIO1_CTRL1 , 0x00000001 );
76+ cs35l41_irq_release (cs35l41 );
6177 break ;
6278 default :
6379 dev_warn (cs35l41 -> dev , "Playback action not supported: %d\n" , action );
@@ -110,10 +126,101 @@ static const struct component_ops cs35l41_hda_comp_ops = {
110126 .unbind = cs35l41_hda_unbind ,
111127};
112128
129+ static irqreturn_t cs35l41_bst_short_err (int irq , void * data )
130+ {
131+ struct cs35l41_hda * cs35l41 = data ;
132+
133+ dev_crit_ratelimited (cs35l41 -> dev , "LBST Error\n" );
134+ set_bit (CS35L41_BST_SHORT_ERR_RLS_SHIFT , & cs35l41 -> irq_errors );
135+
136+ return IRQ_HANDLED ;
137+ }
138+
139+ static irqreturn_t cs35l41_bst_dcm_uvp_err (int irq , void * data )
140+ {
141+ struct cs35l41_hda * cs35l41 = data ;
142+
143+ dev_crit_ratelimited (cs35l41 -> dev , "DCM VBST Under Voltage Error\n" );
144+ set_bit (CS35L41_BST_UVP_ERR_RLS_SHIFT , & cs35l41 -> irq_errors );
145+
146+ return IRQ_HANDLED ;
147+ }
148+
149+ static irqreturn_t cs35l41_bst_ovp_err (int irq , void * data )
150+ {
151+ struct cs35l41_hda * cs35l41 = data ;
152+
153+ dev_crit_ratelimited (cs35l41 -> dev , "VBST Over Voltage error\n" );
154+ set_bit (CS35L41_BST_OVP_ERR_RLS_SHIFT , & cs35l41 -> irq_errors );
155+
156+ return IRQ_HANDLED ;
157+ }
158+
159+ static irqreturn_t cs35l41_temp_err (int irq , void * data )
160+ {
161+ struct cs35l41_hda * cs35l41 = data ;
162+
163+ dev_crit_ratelimited (cs35l41 -> dev , "Over temperature error\n" );
164+ set_bit (CS35L41_TEMP_ERR_RLS_SHIFT , & cs35l41 -> irq_errors );
165+
166+ return IRQ_HANDLED ;
167+ }
168+
169+ static irqreturn_t cs35l41_temp_warn (int irq , void * data )
170+ {
171+ struct cs35l41_hda * cs35l41 = data ;
172+
173+ dev_crit_ratelimited (cs35l41 -> dev , "Over temperature warning\n" );
174+ set_bit (CS35L41_TEMP_WARN_ERR_RLS_SHIFT , & cs35l41 -> irq_errors );
175+
176+ return IRQ_HANDLED ;
177+ }
178+
179+ static irqreturn_t cs35l41_amp_short (int irq , void * data )
180+ {
181+ struct cs35l41_hda * cs35l41 = data ;
182+
183+ dev_crit_ratelimited (cs35l41 -> dev , "Amp short error\n" );
184+ set_bit (CS35L41_AMP_SHORT_ERR_RLS_SHIFT , & cs35l41 -> irq_errors );
185+
186+ return IRQ_HANDLED ;
187+ }
188+
189+ static const struct cs35l41_irq cs35l41_irqs [] = {
190+ CS35L41_IRQ (BST_OVP_ERR , "Boost Overvoltage Error" , cs35l41_bst_ovp_err ),
191+ CS35L41_IRQ (BST_DCM_UVP_ERR , "Boost Undervoltage Error" , cs35l41_bst_dcm_uvp_err ),
192+ CS35L41_IRQ (BST_SHORT_ERR , "Boost Inductor Short Error" , cs35l41_bst_short_err ),
193+ CS35L41_IRQ (TEMP_WARN , "Temperature Warning" , cs35l41_temp_warn ),
194+ CS35L41_IRQ (TEMP_ERR , "Temperature Error" , cs35l41_temp_err ),
195+ CS35L41_IRQ (AMP_SHORT_ERR , "Amp Short" , cs35l41_amp_short ),
196+ };
197+
198+ static const struct regmap_irq cs35l41_reg_irqs [] = {
199+ CS35L41_REG_IRQ (IRQ1_STATUS1 , BST_OVP_ERR ),
200+ CS35L41_REG_IRQ (IRQ1_STATUS1 , BST_DCM_UVP_ERR ),
201+ CS35L41_REG_IRQ (IRQ1_STATUS1 , BST_SHORT_ERR ),
202+ CS35L41_REG_IRQ (IRQ1_STATUS1 , TEMP_WARN ),
203+ CS35L41_REG_IRQ (IRQ1_STATUS1 , TEMP_ERR ),
204+ CS35L41_REG_IRQ (IRQ1_STATUS1 , AMP_SHORT_ERR ),
205+ };
206+
207+ static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
208+ .name = "cs35l41 IRQ1 Controller" ,
209+ .status_base = CS35L41_IRQ1_STATUS1 ,
210+ .mask_base = CS35L41_IRQ1_MASK1 ,
211+ .ack_base = CS35L41_IRQ1_STATUS1 ,
212+ .num_regs = 4 ,
213+ .irqs = cs35l41_reg_irqs ,
214+ .num_irqs = ARRAY_SIZE (cs35l41_reg_irqs ),
215+ };
216+
113217static int cs35l41_hda_apply_properties (struct cs35l41_hda * cs35l41 )
114218{
115219 struct cs35l41_hw_cfg * hw_cfg = & cs35l41 -> hw_cfg ;
220+ bool using_irq = false;
221+ int irq , irq_pol ;
116222 int ret ;
223+ int i ;
117224
118225 if (!cs35l41 -> hw_cfg .valid )
119226 return - EINVAL ;
@@ -145,14 +252,36 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
145252 case CS35L41_NOT_USED :
146253 break ;
147254 case CS35L41_INTERRUPT :
255+ using_irq = true;
148256 break ;
149257 default :
150258 dev_err (cs35l41 -> dev , "Invalid GPIO2 function %d\n" , hw_cfg -> gpio2 .func );
151259 return - EINVAL ;
152260 }
153261 }
154262
155- cs35l41_gpio_config (cs35l41 -> regmap , hw_cfg );
263+ irq_pol = cs35l41_gpio_config (cs35l41 -> regmap , hw_cfg );
264+
265+ if (cs35l41 -> irq && using_irq ) {
266+ ret = devm_regmap_add_irq_chip (cs35l41 -> dev , cs35l41 -> regmap , cs35l41 -> irq ,
267+ IRQF_ONESHOT | IRQF_SHARED | irq_pol ,
268+ 0 , & cs35l41_regmap_irq_chip , & cs35l41 -> irq_data );
269+ if (ret )
270+ return ret ;
271+
272+ for (i = 0 ; i < ARRAY_SIZE (cs35l41_irqs ); i ++ ) {
273+ irq = regmap_irq_get_virq (cs35l41 -> irq_data , cs35l41_irqs [i ].irq );
274+ if (irq < 0 )
275+ return irq ;
276+
277+ ret = devm_request_threaded_irq (cs35l41 -> dev , irq , NULL ,
278+ cs35l41_irqs [i ].handler ,
279+ IRQF_ONESHOT | IRQF_SHARED | irq_pol ,
280+ cs35l41_irqs [i ].name , cs35l41 );
281+ if (ret )
282+ return ret ;
283+ }
284+ }
156285
157286 return cs35l41_hda_channel_map (cs35l41 -> dev , 0 , NULL , 1 , & hw_cfg -> spk_pos );
158287}
@@ -296,6 +425,9 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
296425 struct cs35l41_hda * cs35l41 ;
297426 int ret ;
298427
428+ BUILD_BUG_ON (ARRAY_SIZE (cs35l41_irqs ) != ARRAY_SIZE (cs35l41_reg_irqs ));
429+ BUILD_BUG_ON (ARRAY_SIZE (cs35l41_irqs ) != CS35L41_NUM_IRQ );
430+
299431 if (IS_ERR (regmap ))
300432 return PTR_ERR (regmap );
301433
0 commit comments