1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl 4 * 5 * Copyright (c) 2025 MediaTek Inc. 6 * Author: Darren Ye <darren.ye@mediatek.com> 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/regmap.h> 11 #include <linux/mfd/syscon.h> 12 13 #include "mt8196-afe-clk.h" 14 #include "mt8196-afe-common.h" 15 16 static const char *aud_clks[MT8196_CLK_NUM] = { 17 /* vlp clk */ 18 [MT8196_CLK_VLP_MUX_AUDIOINTBUS] = "top_aud_intbus", 19 [MT8196_CLK_VLP_MUX_AUD_ENG1] = "top_aud_eng1", 20 [MT8196_CLK_VLP_MUX_AUD_ENG2] = "top_aud_eng2", 21 [MT8196_CLK_VLP_MUX_AUDIO_H] = "top_aud_h", 22 /* pll */ 23 [MT8196_CLK_TOP_APLL1_CK] = "apll1", 24 [MT8196_CLK_TOP_APLL2_CK] = "apll2", 25 /* divider */ 26 [MT8196_CLK_TOP_APLL12_DIV_I2SIN0] = "apll12_div_i2sin0", 27 [MT8196_CLK_TOP_APLL12_DIV_I2SIN1] = "apll12_div_i2sin1", 28 [MT8196_CLK_TOP_APLL12_DIV_FMI2S] = "apll12_div_fmi2s", 29 [MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M] = "apll12_div_tdmout_m", 30 [MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B] = "apll12_div_tdmout_b", 31 /* mux */ 32 [MT8196_CLK_TOP_ADSP_SEL] = "top_adsp", 33 }; 34 35 int mt8196_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk) 36 { 37 int ret; 38 39 ret = clk_prepare_enable(clk); 40 if (ret) { 41 dev_err(afe->dev, "failed to enable clk\n"); 42 return ret; 43 } 44 45 return 0; 46 } 47 EXPORT_SYMBOL_GPL(mt8196_afe_enable_clk); 48 49 void mt8196_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk) 50 { 51 if (clk) 52 clk_disable_unprepare(clk); 53 else 54 dev_err(afe->dev, "NULL clk\n"); 55 } 56 EXPORT_SYMBOL_GPL(mt8196_afe_disable_clk); 57 58 static int mt8196_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, 59 unsigned int rate) 60 { 61 int ret; 62 63 if (clk) { 64 ret = clk_set_rate(clk, rate); 65 if (ret) { 66 dev_err(afe->dev, "failed to set clk rate\n"); 67 return ret; 68 } 69 } 70 71 return 0; 72 } 73 74 static unsigned int get_top_cg_reg(unsigned int cg_type) 75 { 76 switch (cg_type) { 77 case MT8196_AUDIO_26M_EN_ON: 78 case MT8196_AUDIO_F3P25M_EN_ON: 79 case MT8196_AUDIO_APLL1_EN_ON: 80 case MT8196_AUDIO_APLL2_EN_ON: 81 return AUDIO_ENGEN_CON0; 82 case MT8196_CG_AUDIO_HOPPING_CK: 83 case MT8196_CG_AUDIO_F26M_CK: 84 case MT8196_CG_APLL1_CK: 85 case MT8196_CG_APLL2_CK: 86 case MT8196_PDN_APLL_TUNER2: 87 case MT8196_PDN_APLL_TUNER1: 88 return AUDIO_TOP_CON4; 89 default: 90 return 0; 91 } 92 } 93 94 static unsigned int get_top_cg_mask(unsigned int cg_type) 95 { 96 switch (cg_type) { 97 case MT8196_AUDIO_26M_EN_ON: 98 return AUDIO_26M_EN_ON_MASK_SFT; 99 case MT8196_AUDIO_F3P25M_EN_ON: 100 return AUDIO_F3P25M_EN_ON_MASK_SFT; 101 case MT8196_AUDIO_APLL1_EN_ON: 102 return AUDIO_APLL1_EN_ON_MASK_SFT; 103 case MT8196_AUDIO_APLL2_EN_ON: 104 return AUDIO_APLL2_EN_ON_MASK_SFT; 105 case MT8196_CG_AUDIO_HOPPING_CK: 106 return CG_AUDIO_HOPPING_CK_MASK_SFT; 107 case MT8196_CG_AUDIO_F26M_CK: 108 return CG_AUDIO_F26M_CK_MASK_SFT; 109 case MT8196_CG_APLL1_CK: 110 return CG_APLL1_CK_MASK_SFT; 111 case MT8196_CG_APLL2_CK: 112 return CG_APLL2_CK_MASK_SFT; 113 case MT8196_PDN_APLL_TUNER2: 114 return PDN_APLL_TUNER2_MASK_SFT; 115 case MT8196_PDN_APLL_TUNER1: 116 return PDN_APLL_TUNER1_MASK_SFT; 117 default: 118 return 0; 119 } 120 } 121 122 static unsigned int get_top_cg_on_val(unsigned int cg_type) 123 { 124 switch (cg_type) { 125 case MT8196_AUDIO_26M_EN_ON: 126 case MT8196_AUDIO_F3P25M_EN_ON: 127 case MT8196_AUDIO_APLL1_EN_ON: 128 case MT8196_AUDIO_APLL2_EN_ON: 129 return get_top_cg_mask(cg_type); 130 case MT8196_CG_AUDIO_HOPPING_CK: 131 case MT8196_CG_AUDIO_F26M_CK: 132 case MT8196_CG_APLL1_CK: 133 case MT8196_CG_APLL2_CK: 134 case MT8196_PDN_APLL_TUNER2: 135 case MT8196_PDN_APLL_TUNER1: 136 return 0; 137 default: 138 return 0; 139 } 140 } 141 142 static unsigned int get_top_cg_off_val(unsigned int cg_type) 143 { 144 switch (cg_type) { 145 case MT8196_AUDIO_26M_EN_ON: 146 case MT8196_AUDIO_F3P25M_EN_ON: 147 case MT8196_AUDIO_APLL1_EN_ON: 148 case MT8196_AUDIO_APLL2_EN_ON: 149 return 0; 150 case MT8196_CG_AUDIO_HOPPING_CK: 151 case MT8196_CG_AUDIO_F26M_CK: 152 case MT8196_CG_APLL1_CK: 153 case MT8196_CG_APLL2_CK: 154 case MT8196_PDN_APLL_TUNER2: 155 case MT8196_PDN_APLL_TUNER1: 156 return get_top_cg_mask(cg_type); 157 default: 158 return get_top_cg_mask(cg_type); 159 } 160 } 161 162 static int mt8196_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type) 163 { 164 int ret; 165 unsigned int reg = get_top_cg_reg(cg_type); 166 unsigned int mask = get_top_cg_mask(cg_type); 167 unsigned int val = get_top_cg_on_val(cg_type); 168 169 if (!afe->regmap) { 170 dev_err(afe->dev, "afe regmap is null !!!\n"); 171 return 0; 172 } 173 174 dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val); 175 176 ret = regmap_update_bits(afe->regmap, reg, mask, val); 177 if (ret) 178 dev_err(afe->dev, "regmap_update_bits failed: %d\n", ret); 179 180 return ret; 181 } 182 183 static int mt8196_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type) 184 { 185 int ret; 186 unsigned int reg = get_top_cg_reg(cg_type); 187 unsigned int mask = get_top_cg_mask(cg_type); 188 unsigned int val = get_top_cg_off_val(cg_type); 189 190 if (!afe->regmap) { 191 dev_err(afe->dev, "afe regmap is null !!!\n"); 192 return 0; 193 } 194 195 dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val); 196 197 ret = regmap_update_bits(afe->regmap, reg, mask, val); 198 if (ret) 199 dev_err(afe->dev, "regmap_update_bits failed: %d\n", ret); 200 201 return ret; 202 } 203 204 static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) 205 { 206 struct mt8196_afe_private *afe_priv = afe->platform_priv; 207 int apll_rate; 208 int ret; 209 210 dev_dbg(afe->dev, "enable: %d\n", enable); 211 212 if (enable) { 213 apll_rate = mt8196_get_apll_rate(afe, MT8196_APLL1); 214 215 /* 180.6336 / 4 = 45.1584MHz */ 216 ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]); 217 if (ret) 218 return ret; 219 220 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1], 221 MT8196_AUD_ENG1_CLK); 222 if (ret) 223 return ret; 224 225 ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]); 226 if (ret) 227 return ret; 228 229 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H], 230 apll_rate); 231 if (ret) 232 return ret; 233 } else { 234 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1], 235 MT8196_AFE_26M); 236 if (ret) 237 return ret; 238 239 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]); 240 241 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H], 242 MT8196_AFE_26M); 243 if (ret) 244 return ret; 245 246 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]); 247 } 248 249 return 0; 250 } 251 252 static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) 253 { 254 struct mt8196_afe_private *afe_priv = afe->platform_priv; 255 int apll_rate; 256 int ret; 257 258 dev_dbg(afe->dev, "enable: %d\n", enable); 259 260 if (enable) { 261 apll_rate = mt8196_get_apll_rate(afe, MT8196_APLL2); 262 263 /* 196.608 / 4 = 49.152MHz */ 264 ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]); 265 if (ret) 266 return ret; 267 268 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2], 269 MT8196_AUD_ENG2_CLK); 270 if (ret) 271 return ret; 272 273 ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]); 274 if (ret) 275 return ret; 276 277 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H], 278 apll_rate); 279 if (ret) 280 return ret; 281 } else { 282 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2], 283 MT8196_AFE_26M); 284 if (ret) 285 return ret; 286 287 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]); 288 289 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H], 290 MT8196_AFE_26M); 291 if (ret) 292 return ret; 293 294 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]); 295 } 296 297 return 0; 298 } 299 300 int mt8196_apll1_enable(struct mtk_base_afe *afe) 301 { 302 int ret; 303 304 /* setting for APLL */ 305 apll1_mux_setting(afe, true); 306 307 ret = mt8196_afe_enable_top_cg(afe, MT8196_CG_APLL1_CK); 308 if (ret) 309 goto err_clk_apll1; 310 311 ret = mt8196_afe_enable_top_cg(afe, MT8196_PDN_APLL_TUNER1); 312 if (ret) 313 goto err_clk_apll1_tuner; 314 315 /* sel 44.1kHz:1, apll_div:7, upper bound:3 */ 316 regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 317 XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT, 318 (0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) | 319 (3 << UPPER_BOUND_SFT)); 320 321 /* apll1 freq tuner enable */ 322 regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 323 FREQ_TUNER_EN_MASK_SFT, 324 0x1 << FREQ_TUNER_EN_SFT); 325 326 /* audio apll1 on */ 327 mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON); 328 329 return 0; 330 331 err_clk_apll1_tuner: 332 mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER1); 333 err_clk_apll1: 334 mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL1_CK); 335 return ret; 336 } 337 338 void mt8196_apll1_disable(struct mtk_base_afe *afe) 339 { 340 /* audio apll1 off */ 341 mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON); 342 343 /* apll1 freq tuner disable */ 344 regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 345 FREQ_TUNER_EN_MASK_SFT, 346 0x0); 347 348 mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER1); 349 mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL1_CK); 350 apll1_mux_setting(afe, false); 351 } 352 353 int mt8196_apll2_enable(struct mtk_base_afe *afe) 354 { 355 int ret; 356 357 /* setting for APLL */ 358 apll2_mux_setting(afe, true); 359 360 ret = mt8196_afe_enable_top_cg(afe, MT8196_CG_APLL2_CK); 361 if (ret) 362 goto err_clk_apll2; 363 364 ret = mt8196_afe_enable_top_cg(afe, MT8196_PDN_APLL_TUNER2); 365 if (ret) 366 goto err_clk_apll2_tuner; 367 368 /* sel 48kHz: 2, apll_div: 7, upper bound: 3*/ 369 regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 370 XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT, 371 (0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) | 372 (3 << UPPER_BOUND_SFT)); 373 374 /* apll2 freq tuner enable */ 375 regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 376 FREQ_TUNER_EN_MASK_SFT, 377 0x1 << FREQ_TUNER_EN_SFT); 378 379 /* audio apll2 on */ 380 mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON); 381 return 0; 382 383 err_clk_apll2_tuner: 384 mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER2); 385 err_clk_apll2: 386 mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL2_CK); 387 return 0; 388 } 389 390 void mt8196_apll2_disable(struct mtk_base_afe *afe) 391 { 392 /* audio apll2 off */ 393 mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON); 394 395 /* apll2 freq tuner disable */ 396 regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 397 FREQ_TUNER_EN_MASK_SFT, 398 0x0); 399 400 mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER2); 401 mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL2_CK); 402 apll2_mux_setting(afe, false); 403 } 404 405 int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll) 406 { 407 struct mt8196_afe_private *afe_priv = afe->platform_priv; 408 int clk_id = 0; 409 410 if (apll < MT8196_APLL1 || apll > MT8196_APLL2) { 411 dev_warn(afe->dev, "invalid clk id %d\n", apll); 412 return 0; 413 } 414 415 if (apll == MT8196_APLL1) 416 clk_id = MT8196_CLK_TOP_APLL1_CK; 417 else 418 clk_id = MT8196_CLK_TOP_APLL2_CK; 419 420 return clk_get_rate(afe_priv->clk[clk_id]); 421 } 422 423 /* 48K: select APLL2; 44.1k: select APLL1 */ 424 int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate) 425 { 426 return (rate % 8000) ? MT8196_APLL1 : MT8196_APLL2; 427 } 428 429 int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name) 430 { 431 if (strcmp(name, APLL1_W_NAME) == 0) 432 return MT8196_APLL1; 433 434 return MT8196_APLL2; 435 } 436 437 static const int mck_div[MT8196_MCK_NUM] = { 438 [MT8196_I2SIN0_MCK] = MT8196_CLK_TOP_APLL12_DIV_I2SIN0, 439 [MT8196_I2SIN1_MCK] = MT8196_CLK_TOP_APLL12_DIV_I2SIN1, 440 [MT8196_FMI2S_MCK] = MT8196_CLK_TOP_APLL12_DIV_FMI2S, 441 [MT8196_TDMOUT_MCK] = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M, 442 [MT8196_TDMOUT_BCK] = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B, 443 }; 444 445 int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) 446 { 447 struct mt8196_afe_private *afe_priv = afe->platform_priv; 448 int div_clk_id; 449 int ret; 450 451 dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate); 452 453 if (mck_id >= MT8196_MCK_NUM || mck_id < 0) 454 return -EINVAL; 455 456 div_clk_id = mck_div[mck_id]; 457 458 /* enable div, set rate */ 459 if (div_clk_id < 0) { 460 dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id); 461 return -EINVAL; 462 } 463 464 if (div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B) 465 rate *= 16; 466 467 ret = mt8196_afe_enable_clk(afe, afe_priv->clk[div_clk_id]); 468 if (ret) 469 return ret; 470 471 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate); 472 if (ret) 473 return ret; 474 475 return 0; 476 } 477 478 int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id) 479 { 480 struct mt8196_afe_private *afe_priv = afe->platform_priv; 481 int div_clk_id; 482 int ret; 483 484 dev_dbg(afe->dev, "mck_id: %d.\n", mck_id); 485 486 if (mck_id < 0) { 487 dev_err(afe->dev, "mck_id = %d < 0\n", mck_id); 488 return -EINVAL; 489 } 490 491 div_clk_id = mck_div[mck_id]; 492 493 if (div_clk_id < 0) { 494 dev_err(afe->dev, "div_clk_id = %d < 0\n", 495 div_clk_id); 496 return -EINVAL; 497 } 498 499 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], MT8196_AFE_26M); 500 if (ret) 501 return ret; 502 503 mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]); 504 505 return 0; 506 } 507 508 int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe) 509 { 510 struct mt8196_afe_private *afe_priv = afe->platform_priv; 511 int ret; 512 513 /* bus clock for AFE external access, like DRAM */ 514 mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]); 515 516 /* bus clock for AFE internal access, like AFE SRAM */ 517 mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]); 518 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS], 519 MT8196_AFE_26M); 520 if (ret) 521 return ret; 522 523 /* enable audio h clock */ 524 mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]); 525 ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H], 526 MT8196_AFE_26M); 527 if (ret) 528 return ret; 529 530 /* AFE hw clock */ 531 /* IPM2.0: USE HOPPING & 26M */ 532 /* set in the regmap_register_patch */ 533 return 0; 534 } 535 536 int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe) 537 { 538 struct mt8196_afe_private *afe_priv = afe->platform_priv; 539 540 /* IPM2.0: Use HOPPING & 26M */ 541 /* set in the regmap_register_patch */ 542 543 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]); 544 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]); 545 mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]); 546 return 0; 547 } 548 549 int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe) 550 { 551 mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_26M_EN_ON); 552 return 0; 553 } 554 555 int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe) 556 { 557 mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_26M_EN_ON); 558 return 0; 559 } 560 561 int mt8196_init_clock(struct mtk_base_afe *afe) 562 { 563 struct mt8196_afe_private *afe_priv = afe->platform_priv; 564 int i; 565 566 afe_priv->clk = devm_kcalloc(afe->dev, MT8196_CLK_NUM, sizeof(*afe_priv->clk), 567 GFP_KERNEL); 568 if (!afe_priv->clk) 569 return -ENOMEM; 570 571 for (i = 0; i < MT8196_CLK_NUM; i++) { 572 afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); 573 if (IS_ERR(afe_priv->clk[i])) { 574 dev_err(afe->dev, "devm_clk_get %s fail\n", aud_clks[i]); 575 return PTR_ERR(afe_priv->clk[i]); 576 } 577 } 578 579 return 0; 580 } 581 582